如何使用表示状态的函数在F#中获取工作状态机?

时间:2014-10-25 09:29:54

标签: recursion f# state-machine mutual-recursion

我正在尝试在F#中创建一个简单的状态机,但是无法使两个具有循环依赖关系的状态工作。
我有这个州工厂:

open System
let createState produceInput stateSwitchRule nextState = 
    let rec stateFunc() = 
        match produceInput() with
        | x when x = stateSwitchRule -> printfn "%s" "Switching state"; nextState()
        | _  -> printfn "%s" "Bad input. Try again"; stateFunc()
    stateFunc

用于创建两个相互递归的状态:

let rec pongState() = createState Console.ReadLine "go to ping" pingState
      and pingState = createState Console.ReadLine "go to pong" (pongState())

[<EntryPoint>]
let main argv = 
    pingState()
    0

当调用pingState()并输入“go to pong”时,状态将切换为pong。但是当调用输入“go to ping”时,抛出了一个空引用异常 无论如何,选择的方法是否存在?或者我应该以不同的方式对其进行建模?

1 个答案:

答案 0 :(得分:3)

这就是我所做的:

#nowarn "40"

open System

let createState produceInput stateSwitchRule nextState = 
    let rec stateFunc () = 
        match produceInput() with
        | x when x = stateSwitchRule -> printfn "%s" "Switching state"; (nextState()) ()
        | _  -> printfn "%s" "Bad input. Try again"; stateFunc()
    stateFunc

let rec pongState : unit -> (unit -> string) = createState Console.ReadLine "go to ping" (fun () -> pingState)
    and pingState : unit -> (unit -> string) = createState Console.ReadLine "go to pong" (fun () -> pongState)

#nowarn "40"抑制关于检查递归定义的对象的初始化稳健性的警告,nextState函数的不同类型,否则编译器抱怨作为其定义的一部分被评估的值,以及关于状态的多余类型注释因为FSI抱怨他们被推断为通用的。很多抱怨;)

至于对它进行不同的建模 - 我想我会将它包装成一个类型而不是单独使用函数,这似乎更自然。我想使用函数是这里的重点。