【问题标题】:Recursive variable definitions in Python and F# (probably OCaml, too)Python 和 F# 中的递归变量定义(也可能是 OCaml)
【发布时间】:2011-07-04 09:41:21
【问题描述】:

鉴于这些 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 稍后定义)。

附:使用字符串作为状态标识符的选项...

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

...保留无效键的情况(即状态机中的无效消息说明符)。

【问题讨论】:

  • 你正在使用静态类型来创建状态机,Python 是动态类型的。
  • 对不起,让解释器检查尽可能多的东西是一个明智的策略,不管 Python 的非静态类型性质如何。请参阅下面 Duncan 的答案。
  • 我同意小麦。下面的答案无法阻止无效密钥的情况。毕竟我可以拥有包含{message_a: state1, message_b: "anything but a state"} 的字典,而解释器不会检查任何内容。因为在这种情况下,解释器什么都不检查
  • 我问的不是拥有 F# 的类型安全这一不可能完成的任务——我问的是将状态机迁移到 Python 的最佳方法。从 F# 音译时,可能会出现拼写错误:“{message_a: statate1, ...}”,Python 会得到它(与“仅字符串”方法相反)。您所说的是:“是的,Duncan 的建议比字符串方法捕获的要多得多,但是在 Python 中,您无法捕获所有内容”。当然。

标签: python f# ocaml recursive-datastructures


【解决方案1】:
## 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]

【讨论】:

    【解决方案2】:

    在 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 ...
    

    【讨论】:

    • 优秀 - 迄今为止最好的建议。
    猜你喜欢
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多