2011-02-25 72 views
5

鉴于这些F#类型声明...递归变量定义

type Message = 
    | MessageA 
    | MessageB 
    | MessageC 
    | MessageD 

type State = { 
    Name:string 
    NextStateMap: Map<Message,State> 
} 

...有没有这种特定的状态机的一个同样表现定义...

let rec state0 = { Name = "0"; NextStateMap = Map.ofList [ (MessageA,state1); (MessageB,state2)] } 
    and state1 = { Name = "1"; NextStateMap = Map.ofList [ (MessageB,state3)] } 
    and state2 = { Name = "2"; NextStateMap = Map.ofList [ (MessageA,state3)] } 
    and state3 = { Name = "3"; NextStateMap = Map.ofList [ (MessageC,state4)] } 
    and state4 = { Name = "4"; NextStateMap = Map.ofList [ (MessageD,state5)] } 
    and state5 = { Name = "5"; NextStateMap = Map.empty} 

...用Python?请注意,通过“rec”,我们不必按由拓扑排序定义的顺序进行赋值......(例如,state0是根据state1定义的,即使state1是稍后定义的)。

P.S.使用字符串作为国家标识符的选项...

stateMachine = { 
    "0" : { "A":"1", "B":"2"}, 
    "1" : { "B":"3" }, 
... 

...叶子打开无效键(在状态机即无效消息说明符)的情况下。

+2

您使用的静态类型来创建一个状态机,Python是动态类型。 – wheaties 2011-02-25 16:00:51

+0

我很抱歉,尽管解释器检查尽可能多的东西是一个明智的策略,不管Python的非静态类型的本质。请参阅下面Duncan的回答。 – ttsiodras 2011-02-25 16:10:29

+0

我同意wheaties。下面的答案不能阻止无效密钥的情况。毕竟我可以拥有包含“{message_a:state1,message_b:”的任何内容但不是状态的字典},解释器不会检查任何内容。因为解释者_在这种情况下不检查任何东西。 – 2011-02-27 00:48:24

回答

5

在Python中,我想你会定义状态,然后设置地图。像伪代码:

state0 = State("0") 
state1 = State("1") 
... and so on ... 
state0.next_states = {message_a: state1, message_b: state2 } 
state1.next_states = {message_b: state3} 
... and so on ... 
+0

优秀 - 迄今为止最好的建议。 – ttsiodras 2011-02-25 16:07:41

0
## a generic state machine framework ################### 

class Message(object): 
    """ 
    This represents a message being passed to the 
    state machine. 
    """ 
    def __init__(self, name): 
     self.name = name 
    def __str__(self): 
     return "Message(%r)" % self.name 
    def __call__(self, smap): 
     try: 
      return smap[self] 
     except KeyError: 
      raise Exception("invalid message: %s vs %s" 
          % (self, smap)) 

class MessageFactory(object): 
    """ 
    Since python doesn't have symbols, this automagically 
    creates the messages for you. (It's purely for 
    convenience, and you could just as easily instantiate 
    each message by hand. 
    """ 
    cache = {} 
    def __getattr__(self, name): 
     return self.cache.setdefault(name, Message(name)) 

class StateMachine(object): 
    """ 
    This keeps track of the state, of course. :) 
    """ 
    def __init__(self, state): 
     self.state = state 
    def __call__(self, msg): 
     self.state = self.state(msg) 


## how to set it up: ################################### 

msg = MessageFactory() 
state =\ 
{ 
    0 : lambda m: m({ msg.A : state[1], 
         msg.B : state[2] }), 
    1 : lambda m: m({ msg.B : state[3] }), 
    2 : lambda m: m({ msg.A : state[3] }), 
    3 : lambda m: m({ msg.C : state[4] }), 
    4 : lambda m: m({ msg.D : state[5] }), 
    5 : lambda m: m({ }), 
} 

## how to use it: ###################################### 

s = StateMachine(state[0]) 
s(msg.A) 
assert s.state is state[1]