I have been trying to understand the State Monad. Not so much how it is used, though that is not always easy to find, either. But every discussion I find of the State Monad ha
To understand the "second run" let's analyse it "backwards".
The signature def flatMap[B](f: A => State[S, B]): State[S, B]
suggests that we need to run a function f
and return its result.
To execute function f
we need to give it an A
. Where do we get one?
Well, we have run
that can give us A
out of S
, so we need an S
.
Because of that we do: s => val (a, t) = run(s) ...
.
We read it as "given an S
execute the run
function which produces us A
and a new S
. And this is our "first" run.
Now we have an A
and we can execute f
. That's what we wanted and f(a)
gives us a new State[S, B]
.
If we do that then we have a function which takes S
and returns Stats[S, B]
:
(s: S) =>
val (a, t) = run(s)
f(a) //State[S, B]
But function S => State[S, B]
isn't what we want to return! We want to return just State[S, B]
.
How do we do that? We can wrap this function into State
:
State(s => ... f(a))
But it doesn't work because State
takes S => (B, S)
, not S => State[B, S]
.
So we need to get (B, S)
out of State[B, S]
.
We do it by just calling its run
method and providing it with the state we just produced on the previous step!
And it is our "second" run.
So as a result we have the following transformation performed by a flatMap
:
s => // when a state is provided
val (a, t) = run(s) // produce an `A` and a new state value
val resState = f(a) // produce a new `State[S, B]`
resState.run(t) // return `(S, B)`
This gives us S => (S, B)
and we just wrap it with the State
constructor.
Another way of looking at these "two runs" is:
first - we transform the state ourselves with "our" run
function
second - we pass that transformed state to the function f
and let it do its own transformation.
So we kind of "chaining" state transformations one after another. And that's exactly what monads do: they provide us with the ability to schedule computation sequentially.