我试图在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()
并输入"转到pong"时,状态切换到pong。但是当调用输入"转到ping"时,会抛出一个空引用异常
选择的方法是否存在这种情况,或者我应该以不同的方式进行建模?
这就是我所做的:
#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抱怨它们被推断为泛型。很多抱怨;)
至于以不同的方式建模——我想我会把它封装在一个类型中,而不是只使用函数,这似乎更自然。不过,我想使用函数才是重点。