我很好奇是否有一种编程语言将状态机(类似于boost :: statechart)作为主要语言构造。
类比 - c#有委托,其中java使用观察者模式,C有回调。 Perl和python有内置哈希,而C ++和java需要一个库。
更新:
这应该是C ++,C#,Java,Lisp等意义上的通用编程语言......
我的意思是“成熟”的状态机,在Harel形式主义或UML状态图或boost :: statechart的层面上都有所有的铃声和口哨声。
Ragel是一种状态机器语言。 IOW,它不是一种也支持状态机的语言,它是一种只支持状态机的语言。这显然意味着它不是图灵完整的,但谁需要呢?
更准确地说,Ragel是一个状态机编译器,它以类似regexp的语言描述状态机,并用C,C ++,Objective-C,D,Java或Ruby生成该状态机的实现。 (想想yacc
,但是对于状态机而不是LALR(1)表解析器。)Ragel的主要目的是解析二进制协议(例如网络协议或磁盘文件格式),但它也可以用于文本。
使用Ragel的一个着名例子是用于Ruby的Mongrel webserver:它的HTTP内核是用Ragel编写的,这使得它非常快速和安全。事实上,HTTP内核非常好用,它已经在不同的应用程序中重复使用了很多次:Thin,Unicorn和Rainbows也是网络服务器,实际上是Mongrel的直接竞争对手。 Ebb是反向HTTP代理。 RFuzz是一种用于Web应用程序的模糊测试工具。此外,一些安全工具使用它。
Ragel还允许将主机语言中的代码嵌入到状态机中,从而使其成为图灵完备的,并且不仅能识别而且能够解释协议。
通常,通过协程(例如Lua)或continuation(例如Scala)或GOTO
(例如PHP)或正确的尾调用(例如Scheme)支持高级用户定义控制流的每种语言都可用于轻松实现状态机。 (Generators(Python)aka iterators(C#),基本上是“糟糕的协程”,可能会也可能不会工作,这取决于你对“工作”的定义。)以及任何具有灵活语法(例如Ruby)或支持metasyntactic抽象的语言(例如Clojure)可用于描述状态机。 (对非ASCII标识符的支持也有帮助,因此您可以使用状态机的实际箭头。)
这意味着,如果将两者结合使用,并使用支持尾调用和metasyntactic抽象的语言,则可以获得非常好的状态机,而无需本机语言支持。 Shriram Krishnamurthi在首届轻量级语言会议上发表了一篇名为“Perl之前的猪”的着名演讲,其中他演示了在计划中实施FSM。 (这里是slides,audio recording和paper explaining the code)。代码本身是一个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
(这是为true
方案说话)。
Shriram Krishnamurthi有一篇关于using macros to add an embedded sublanguage for automata to Scheme的演讲和论文。不过,我不确定是否有任何Schemes将其宏包含为标准库。
微软研究院最近在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;
}
...
我差不多十年才到派对了,但是我最近偶然发现了一种晦涩难懂的语言,它从FSM中借用了Hume的想法
我不确定它是否仍在积极维护,但你至少可以下载编译器并使用它。信息很难获得,但有一些在线的论文和文章显示了必需品。
基于David Harel的SCXML形式主义(支持分层和并行状态机),有一种新的基于W3C XML的状态机语言StateChart。
Apache Commons有一个Java based implementation of SCXML:
Commons SCXML是一个旨在创建和维护Java SCXML引擎的实现,该引擎能够执行使用SCXML文档定义的状态机,同时抽象出环境接口。
SMC是一个简单的域特定语言的编译器,它将为许多流行语言生成状态机。我用它来生成可维护的状态机,用于各种各样的事情,例如复杂的用户界面和自定义网络协议。
格子编程语言引入了“Typestate-Oriented Programming,这是一种扩展面向对象编程的范式。”
这是doc:http://www.cs.cmu.edu/~aldrich/plaid/
E.g:
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]
{ ... }
}
Erlang的OTP通过'gen_fsm'支持状态机构造。自从我上次查看它已经过了几年,所以我有点生疏,但你可以谷歌为'Erlang gen_fsm'并找到大量的参考资料
不完全,但有一个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()
我刚刚找到一个:AsmL (Abstract State Machine Language)。 这是CodePlex上的page with more info。
有趣的是,它是由微软开发的。
在C#中,迭代器(带有'yield return'和'yield break')是一种直接转换为状态机的语言结构。我实际上并没有这样使用它,但实际上我认为它可以在实践中使用。
碰巧有一个关于它的stackoverflow问题here。尽管投票的答案最高,但不鼓励它......
除了Ragel之外,还有一种技术上有趣但非常模糊的语言SL1。见http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=1095580。它由斯洛文尼亚的Iskratel创建,旨在开发以国家机器为基本块的电信系统。