I am trying to get a grasp on Haskell using the online book Learn you a Haskell for great Good.
I have, to my knowledge, been able to understand Monads so far until I hit the chapter introducing the State Monad.
However, the code presented and claimed to be the Monad implementation of the State type (I have not been able to locate it in Hoogle) seems too much for me to handle.
To begin with, I do not understand the logic behind it i.e why it should work and how the author considered this technique.( maybe relevant articles or white-papers can be suggested?)
At line 4, it is suggested that function f takes 1 parameter.
However a few lines down we are presented with pop, which takes no parameters!To extend on point 1, what is the author trying to accomplish using a function to represent the State.
Any help in understanding what is going on is greatly appreciated.
Edit
To whom it may concern,
The answers below cover my question thoroughly.
One thing I would like to add though:
After reading an article suggested below, I found the answer to my second point above:
All that time I assumed that the pop function would be used like :
stuff >>= pop
since in the bind type the second parameter is the function, whereas the correct usage is this pop >>= stuff
, which I realized after reading again how do-notation translates to plain bind-lambdas.
Short answer:
State
is meant to exploit monads' features in order to simulate an imperative-like system state with local variables. The basic idea is to hide within the monad the activity of taking in the current state and returning the new state together with an intermediate result at each step (and here we haves -> (a,s)
.State
. The former may have whatever type you want (provided that they eventually produce someState a
if you want to use them in the state monad). The latter holds functions of types -> (a,s)
: this is the state-passing layer managed by the monad.State
is actually produced by means of(>>=)
andreturn
as they're defined for theMonad (State s)
instance. Its role is to pass down the state through the calls of your code.Point 3 also is the reason why the state parameter disappears from the functions actually used in the state monad.
Long answer:
The State Monad has been studied in different papers, and exists also in the Haskell framework (I don't remember the good references right now, I'll add them asap).
This is the idea that it follows: consider a type
data MyState = ...
whose values holds the current state of the system.If you want to pass it down through a bunch of functions, you should write every function in such a way that it takes at least the current state as a parameter and returns you a pair with its result (depending on the state and the other input parameters) and the new (possibly modified) state. Well, this is exactly what the type of the state monad tells you:
s -> (a, s)
. In our example,s
isMyState
and is meant to pass down the state of the system.The function wrapped in the
State
does not take parameters except from the current state, which is needed to produce as a result the new state and an intermediate result. The functions with more parameters that you saw in the examples are not a problem, because when you use them in thedo
-notation within the monad, you'll apply them to all the "extra" needed parameters, meaning that each of them will result in a partially applied function whose unique remaining parameter is the state; the monad instance forState
will do the rest.If you look at the type of the functions (actually, within monads they are usually called actions) that may be used in the monad, you'll see that they result type is boxed within the monad: this is the point that tells you that once you give them all the parameters, they will actually do not return you the result, but (in this case) a function
s -> (a,s)
that will fit within the monad's composition laws.The computation will be executed by passing to the whole block/composition the first/initial state of the system.
Finally, functions that do not take parameters will have a type like
State a
wherea
is their return type: if you have a look at the value constructor forState
, you'll see again that this is actually a functions -> (a,s)
.I'm total newbie to Haskell and I couldn't understand well the State Monad code in that book, too. But let me add my answer here to help someone in the future.
Answers:
What are they trying to accomplish with State Monad ?
Composing functions which handle stateful computation.
e.g.
push 3 >>= \_ -> push 5 >>= \_ -> pop
Why
pop
takes no parameters, while it is suggested functionf
takes 1 parameter ?pop
takes no arguments because it is wrapped byState
.unwapped function which type is
s -> (a, s)
takes one argument. the same goes forpush
.you can unwrapp with
runState
.if you mean the right-hand side of the
>>=
by the "functionf
", thef
will be like\a -> pop
or\a -> push 3
, not justpop
.Long Explanation:
These 3 things helped me to understand State Monad and the Stack example a little more.
Consider the types of the arguments for bind operator(
>>=
)The definition of the bind operator in Monad typeclass is this
In the Stack example,
m
isState Stack
.If we mentaly replace
m
withState Stack
, the definition can be like this.Therefore, the type of left side argument for the bind operator will be
State Stack a
.And that of right side will be
a -> State Stack b
.Translate do notation to bind operator
Here is the example code using do notation in the book.
it can be translated to the following code with bind operator.
Now we can see what will be the right-hand side for the bind operator.
Their types are
a -> State Stack b
.Recognize the difference between
(State s)
and(State h)
in the instance declarationHere is the instance declaration for State in the book.
Considering the types with the Stack example, the type of
(State s)
will beAnd the type of
(State h)
will be(State h)
is the left-hand side argument of the bind operator and its type isState Stack a
as described above.Then why
h
becomesStack -> (a, Stack)
?It is the result of pattern matching against the State value constructor which is defined in the newtype wrapper. The same goes for the
(State g)
.In general, type of
h
iss ->(a, s)
, representation of the stateful computation. Any of followings could be theh
in the Stack example.that's it.
The
State
monad represents stateful computations i.e. computations that use values from, and perhaps modify, some external state. When you sequence stateful computations together, the later computations might give different results depending on how the previous computations modified the state.Since functions in Haskell must be pure (i.e. have no side effects) we simulate the effect of external state by demanding that every function takes an additional parameter representing the current state of the world, and returns an additional value, representing the modified state. In effect, the external state is threaded through a sequence of computations, as in this abomination of a diagram that I just drew in MSPaint:
Notice how each box (representing a computation) has one input and two outputs.
If you look at the
Monad
instance forState
you see that the definition of(>>=)
tells you how to do this threading. It says that to bind a stateful computationc0
to a functionf
that takes results of a stateful computation and returns another stateful computation, we do the following:c0
using the initial states0
to get a result and a new state:(val, s1)
val
to the functionf
to get a new stateful computation,c1
c1
with the modified states1
How does this work with functions that already take
n
arguments? Because every function in Haskell is curried by default, we simply tack an extra argument (for the state) onto the end, and instead of the normal return value, the function now returns a pair whose second element is the newly modified state. So instead ofwe now have
You might choose to think of as
which is the same thing in Haskell (since function composition is right associative) which reads "
f
is a function which takes an argument of typea
and returns a stateful computation". And that's really all there is to theState
monad.The
State
monad is essentiallya function from one state (
s
) to a pair of the desired result (a
) and a new state. The implementation makes the threading of the state implicit and handles the state-passing and updating for you, so there's no risk of accidentally passing the wrong state to the next function.Thus a function that takes
k > 0
arguments, one of which is a state and returns a pair of something and a new state, in theState s
monad becomes a function takingk-1
arguments and returning a monadic action (which basically is a function taking one argument, the state, here).In the non-State setting,
pop
takes one argument, the stack, which is the state. So in the monadic setting,pop
becomes aState Stack Int
action taking no explicit argument.Using the
State
monad instead of explicit state-passing makes for cleaner code with fewer opportunities for error, that's what theState
monad accomplishes. Everything could be done without it, it would just be more cumbersome and error-prone.