我想知道是否有一种编程语言,其主要语言结构是状态机(类似于boost::statechart)。
类比 - c#使用委托,Java使用观察者模式,C使用回调函数。Perl和Python具有内置哈希表,而C++和Java需要库。
更新:
这应该是通用的编程语言,例如C++、C#、Java、Lisp等。
我指的是“成熟”的状态机,具有Harel形式主义或UML状态图或boost::statechart的所有功能。
我想知道是否有一种编程语言,其主要语言结构是状态机(类似于boost::statechart)。
类比 - c#使用委托,Java使用观察者模式,C使用回调函数。Perl和Python具有内置哈希表,而C++和Java需要库。
更新:
这应该是通用的编程语言,例如C++、C#、Java、Lisp等。
我指的是“成熟”的状态机,具有Harel形式主义或UML状态图或boost::statechart的所有功能。
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标识符也有帮助,这样你可以使用实际箭头来表示状态机。)(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
)。
Commons SCXML是一个实现,旨在创建和维护一个Java SCXML引擎,能够执行使用SCXML文档定义的状态机,并抽象出环境接口。
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]
{ ... }
}
微软研究院最近在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;
}
...
Erlang的OTP通过'gen_fsm'支持状态机构造。我上一次看它已经是几年前的事了,所以有些生疏,但你可以在谷歌上搜索'Erlang gen_fsm'并找到大量的参考资料。
#!/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()