I am trying to understand the State monad and I am mighty confused I must admit. I created a Computational Expression and added a lots of print statements so I can follow up who gets called when.
type State<'st,'a> =
| Ok of 'a * 'st
| Error of string
and StateMonadBuilder() =
member b.Return(x) = printfn "100 Return %A" x; fun s -> Ok (x, s)
member b.ReturnFrom(x) = printfn "100 ReturnFrom %A" x; x
member b.Bind(p, rest) =
printfn "100 Bind:: %A %A" p rest
fun state ->
printfn "200 Bind:: %A %A" p rest
let result = p state in
match result with
| Ok (value,state2) -> (rest value) state2
| Error msg -> Error msg
member b.Get () =
printfn "100 Get"
fun state ->
printfn "200 Get :: %A" state
Ok (state, state)
member b.Put s = fun state -> Ok ((), s)
let state = StateMonadBuilder()
let turn () =
state {
printfn "100 turn::"
let! pos1 = state.Get()
printfn "200 turn:: %A" pos1
let! pos2 = state.Get()
printfn "300 turn:: %A" pos1
return! state.Put(fst pos1, snd pos1 - 1)
}
let move () =
state {
printfn "100 move::"
let! x = turn()
printfn "200 move:: %A" x
let! y = turn()
printfn "200 move:: %A" y
return x
}
let run () =
state {
printfn "100 run::"
do! move()
}
run () (5,5) |> ignore
The above code prints the following output
100 run::
100 move::
100 turn::
100 Get
100 Bind:: <fun:Get@301> <fun:turn@312>
100 Bind:: <fun:Bind@292-2> <fun:move@322>
100 Bind:: <fun:Bind@292-2> <fun:run@329>
200 Bind:: <fun:Bind@292-2> <fun:run@329>
200 Bind:: <fun:Bind@292-2> <fun:move@322>
200 Bind:: <fun:Get@301> <fun:turn@312>
200 Get :: (5, 5)
200 turn:: (5, 5)
100 Get
100 Bind:: <fun:Get@301> <fun:turn@314-1>
200 Bind:: <fun:Get@301> <fun:turn@314-1>
200 Get :: (5, 5)
300 turn:: (5, 5)
100 ReturnFrom <fun:Put@304>
200 move:: <null>
100 Return <null>
100 Return <null>
I understand the first 5 lines of this output. Obviously run
calls move
calls turn
calls Get
.
And then there is a let! pos1 = ...
which triggers the call to Bind
. So far so good. But then there are additional calls to Bind
.
How do they come into existence?
I understand on a superficial level that binding into those outer contexts must be somehow the magic of the state monad but how does this mechanism work?
And then there is another let! pos2 = ...
in the function turn
which also triggers Bind
but this time only once not 3 times as before!
Looking forward to your explainations