有没有一种编程语言内置状态机构造?

36

我想知道是否有一种编程语言,其主要语言结构是状态机(类似于boost::statechart)。

类比 - c#使用委托,Java使用观察者模式,C使用回调函数。Perl和Python具有内置哈希表,而C++和Java需要库。

更新:

这应该是通用的编程语言,例如C++、C#、Java、Lisp等。

我指的是“成熟”的状态机,具有Harel形式主义或UML状态图或boost::statechart的所有功能。

15个回答

53

Ragel 是一种状态机语言。也就是说,它不是一种同时支持状态机的语言,而是仅支持状态机的语言。这显然意味着它不是图灵完备的,但谁需要那个呢?

更准确地说,Ragel 是一个状态机编译器,它使用类似于正则表达式的语言描述状态机,并在 C、C++、Objective-C、D、Java 或 Ruby 中生成该状态机的实现。(想想 LALR(1) 表解析器的状态机版本中的 yacc。) Ragel 的主要目的是解析二进制协议(如网络协议或磁盘文件格式),但同样适用于文本。

使用 Ragel 的一个著名例子是 Mongrel Web 服务器 for Ruby:它的 HTTP 内核是用 Ragel 编写的,这使它非常快速和安全。事实上,HTTP 内核非常好,以至于已经在不同的应用程序中多次重复使用:Thin、Unicorn 和 Rainbows 也是 Web 服务器,并且实际上是 Mongrel 的直接竞争对手。Ebb 是一个反向 HTTP 代理。RFuzz 是一个 Web 应用程序的模糊测试工具。此外,一些安全工具也使用它。

Ragel 还允许将主机语言中的代码嵌入状态机中,从而使其成为图灵完备的,并且能够不仅识别协议,还能解释协议。

一般来说,任何支持通过协程(例如Lua)或续延(例如Scala)或GOTO(例如PHP)或适当的尾调用(例如Scheme)实现高级用户定义控制流的语言都可以用于轻松地实现状态机。(生成器(Python)也就是迭代器(C#),它们基本上是“劣质协程”,可能会或可能不会工作,这取决于你对“工作”的定义。)而任何具有灵活语法(例如Ruby)或支持元语法抽象(例如Clojure)的语言都可以用于描述状态机。(支持非ASCII标识符也有帮助,这样你可以使用实际箭头来表示状态机。)
这意味着,如果你将两者结合起来,并使用支持尾调用和元语法抽象的语言,你可以获得非常好的状态机,而不需要本地语言支持。Shriram Krishnamurthi在首届轻量级语言会议上发表了一场现在(有点)著名的演讲,题为“Perl之前的猪”,在其中他展示了在Scheme中实现FSM的方法。(这里是幻灯片音频记录解释代码的论文)。代码本身是一个26行(实际上是非常短的行)的宏,允许您编写如下代码:
(define my-regex
  (automaton init
             [init : (c → more)]
             [more : (a → more)
                     (d → more)
                     (r → end)]
             [end : accept]))

这是与正则表达式c(a|d)*r对应的状态机规范。它不仅仅是一份规范,还是一个可运行的程序,实现了该状态机。
我可以这样调用它:
(my-regex '(c a d a d d r))

在这种情况下,获得结果#t(Scheme语言中的true)。


https://github.com/adrian-thurston/ragel - Joe Bowbeer

10
有一种名为SCXML的新型基于W3C XML的状态机语言,基于David Harel的StateChart形式化方法(支持分层和并行状态机)。
Apache Commons有一个基于Java实现的SCXML

Commons SCXML是一个实现,旨在创建和维护一个Java SCXML引擎,能够执行使用SCXML文档定义的状态机,并抽象出环境接口。


5

Plaid编程语言引入了“类型状态导向编程”,这是一种将面向对象编程与类型状态相结合的范式。

以下是相关文档:http://www.cs.cmu.edu/~aldrich/plaid/

例如:

state File {
    public final String filename;
}

state OpenFile extends File {
    private CFilePtr filePtr;
    public int read() { ... }
    public void close() [OpenFile>>ClosedFile]
        { ... }
}

state ClosedFile extends File {
    public void open() [ClosedFile>>OpenFile]
        { ... }
}

4

SMC是一个编译器,用于生成许多流行语言的状态机,它针对简单的领域特定语言。我已经使用它来生成可维护的状态机,用于各种事情,例如复杂的用户界面和自定义网络协议。


3

微软研究院最近在GitHub上发布了P语言。此外,他们还提供了PSharp框架,该框架提供了C#扩展库和用于语言编译器的高级语法。

我很期待尝试它。

这里是他们示例中C#扩展的一部分:

internal class Server : Machine
{
    MachineId Client;

    [Start]
    [OnEntry(nameof(InitOnEntry))]
    class Init : MachineState { }

    void InitOnEntry()
    {
        ...
        this.Goto(typeof(Active));
    }

    ...

这里是他们高级语法的一部分:
using System;

namespace TheStateMachine
{
  internal machine Client
  {
    private machine Server;
    private start state Init
    {
      entry
      {
        this.Server = (trigger as Config).target;
        jump(Playing);
      }
    }

    private state Playing
    {
      entry
      {
        //execute logic
      }
      on AnotherEvent goto AnotherState;
      on SomeEvent do ProcessSomeLogic;
    }

  ...

3

3
这可能不是 OP 寻找的内容。他询问的是 FSMs 而不是 ASMs。ASMs 是完全不同的东西,它们是一种正式的规范机制,用于证明程序的定理。另外,顺便提一下,微软雇用了几位领先的程序验证科学家,包括 Tony Hoare。(考虑到 Windows 中的一个错误可能会导致全球经济崩溃,这并不令人惊讶。)因此,这并不是很令人惊讶,这来自于 Microsoft。还要注意,这是微软研究院,而不是微软公司,两者是完全不同的实体。 - Jörg W Mittag

3

Erlang的OTP通过'gen_fsm'支持状态机构造。我上一次看它已经是几年前的事了,所以有些生疏,但你可以在谷歌上搜索'Erlang gen_fsm'并找到大量的参考资料。


gen_fsm现已被弃用,取而代之的是更好的gen_statem行为模块。 - Vance Shipley

2
并不完全如此,但是Python有一个状态机模块,可以使用装饰器来支持实现Harel风格的状态图,包括具有多个状态的上下文、嵌套子状态(带或不带历史记录)。代码最终看起来像下面这样。模块在http://wiki.python.org/moin/State%20Machine%20via%20Decorators
 #!/bin/env/python
"""
This example now works. The state pattern module
allows defining states which are their their own context for 
implementing substates.  Substate Medium (class Medium) shows this here.
"""
"""
Example with 5 buttons. Two ,'up','down' cause state to rotate among the
several states.  The other three, bx,by,bz, invoke state dependent behavior.

Switching into a state causes the labels of the three buttons bx,by,bz to
change.  Pressing one of the buttons causes associated text to appear in
corresponding static text box. An 'onEnter' method changes the text.
"""
import wx
import DecoratorStateMachine as dsm

class MyFrame(wx.Frame, dsm.ContextBase):

   xtable = dsm.TransitionTable('pstate')


   def __init__(self):
      MyFrame.xtable.initialize(self)

      wx.Frame.__init__(self, None, -1, "My Frame", size=(470,220))

      family = wx.SWISS
      style = wx.NORMAL
      weight = wx.BOLD
      font = wx.Font(11,family,style,weight, False, "Verdana")
      self.SetFont(font)

      panel = wx.Panel(self, -1)

      b = wx.Button(panel, -1, "Up", pos=(50,20), size=(80,35))
      self.Bind(wx.EVT_BUTTON, self.OnUp, b)
      b.SetDefault()

      b = wx.Button(panel, -1, "Down", pos=(50,60), size=(80,35))
      self.Bind(wx.EVT_BUTTON, self.OnDown, b)

      self.bx = wx.Button(panel, -1, "xxx", pos=(50,100), size=(110,35))
      self.Bind(wx.EVT_BUTTON, self.OnBA, self.bx)
      self.tx = wx.StaticText(panel, -1, "", pos=(50,140), size=(110,35))

      self.by = wx.Button(panel, -1, "yyy", pos=(180,100), size=(110,35))
      self.Bind(wx.EVT_BUTTON, self.OnBB, self.by)
      self.ty = wx.StaticText(panel, -1, "", pos=(180,140), size=(110,35))

      self.bz = wx.Button(panel, -1, "zzz", pos=(310,100), size=(110,35))
      self.Bind(wx.EVT_BUTTON, self.OnBC, self.bz )
      self.tz = wx.StaticText(panel, -1, "", pos=(310,140), size=(110,35))


   @dsm.transition(xtable)
   def OnUp(self, event):
      pass

   @dsm.transition(xtable)
   def OnDown(self, event):
      pass

   @dsm.event(xtable)
   def OnBA(self, event):
      pass

   @dsm.event(xtable)
   def OnBB(self, event):
      pass

   @dsm.event(xtable)
   def OnBC(self, event):
      self.tz.SetLabel("Bossy")


class Off(MyFrame):
   "This is state Off "

   def onEnter(self):
      self.bx.SetLabel("Chase")
      self.by.SetLabel("Onry")
      self.bz.SetLabel("Cow")

   def OnBA(self, event):
      self.tx.SetLabel("Chase the")

   def OnBB(self, event):
      self.ty.SetLabel("Onry")


class Low(MyFrame):
   "This is state Low "
   items = ["Walk", "Green", "Llama"]

    def onEnter(self):
      self.bx.SetLabel(self.items[0])
      self.by.SetLabel(self.items[1])
      self.bz.SetLabel(self.items[2])

   def OnBA(self, event):
      self.tx.SetLabel("Walk the ")

   def OnBB(self, event):
      self.ty.SetLabel(self.items[1])

   def OnBC(self, event):
      self.tz.SetLabel(self.items[2])


class Medium(MyFrame):
   "This is state Medium "
   ytable = dsm.TransitionTable('qstate')

   def onEnter(self):
      if not hasattr(self, 'qstate'):    #unconditionally initialize for no history
         self.ytable.initialize(self)
      self.doEnter()

   @dsm.event(ytable)
   def doEnter(): pass

   @dsm.transitionevent(ytable)
   def OnBA(self, event):
      pass

   @dsm.transitionevent(ytable)
   def OnBB(self, event):
      pass

   @dsm.transitionevent(ytable)
   def OnBC(self, event):
      pass


class High(Low):
   "This is state High "

   items = ["Pet","Tame", "Dog"]

   def OnBA(self, event):
      self.tx.SetLabel("Pet his")

class MedBlue(Medium):
   """State med blu"""

   items = ["Med BLue","Checkered", "Tractor"]

   def onEnter(self):
      self.bx.SetLabel(self.items[0])
      self.by.SetLabel(self.items[1])
      self.bz.SetLabel(self.items[2])

   def doEnter(self):
      self.onEnter()

   def OnBA(self, event):
      self.tx.SetLabel("Med Blue")
   def OnBB(self, event):
      self.ty.SetLabel("Chekered")
   def OnBC(self, event):
      self.tz.SetLabel("Tractor")


class MedRed(Medium):
   """State med red"""

   items = ["Med Red","Striped", "Combine"]

   def onEnter(self):
      self.bx.SetLabel(self.items[0])
      self.by.SetLabel(self.items[1])
      self.bz.SetLabel(self.items[2])

   def doEnter(self):
      self.onEnter()

   def OnBA(self, event):
      self.tx.SetLabel("Med Red")
   def OnBB(self, event):
      self.ty.SetLabel("Striped")
   def OnBC(self, event):
      self.tz.SetLabel("Combine")


MyFrame.xtable.nextStates(Low, (Medium,Off))
MyFrame.xtable.nextStates(Medium, (High,Low))
MyFrame.xtable.nextStates(High, (Off,Medium))
MyFrame.xtable.nextStates(Off, (Low,High))
MyFrame.xtable.initialstate = Off

Medium.ytable.nextStates(MedBlue, (MedBlue, MedRed, MedRed))
Medium.ytable.nextStates(MedRed,  (MedBlue, MedBlue, MedRed))
Medium.ytable.initialstate = MedBlue


if __name__=='__main__':
   app = wx.PySimpleApp()
   frame = MyFrame()
   frame.Show(True)
   app.MainLoop()

2
2015年9月,xstate 项目推出。它实现了SCXML,并旨在为现代Web提供JavaScript和TypeScript有限状态机和状态图。文档链接

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接