I'm trying to create a simple state machine in F# but having trouble getting two states with circular dependencies to work.
I have this state factory:
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
which I use to create two mutually recursive states:
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
When invoking pingState()
and inputting "go to pong" the state is switched to pong. But when invoking inputting "go to ping" a null reference exception is thrown.
Is there anyway around this with the chosen approach or should I model it differently?
This is what I did:
#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"
to suppress the warning about checking recursively defined objects for initialization soundness, different type for the nextState function, otherwise the compiler complained about a value being evaluated as a part of its definition, and superfluous type annotations on states because FSI complained about them being inferred to be generic. Lots of complaints ;)
As for modelling it differently - I think I would wrap it in a type instead of using solely functions, it seems more natural. I guess using functions was the whole point here though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With