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 hi
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.
Composing functions which handle stateful computation.
e.g. push 3 >>= \_ -> push 5 >>= \_ -> pop
pop
takes no parameters, while it is suggested function f
takes 1 parameter ?pop
takes no arguments because it is wrapped by State
.
unwapped function which type is s -> (a, s)
takes one argument. the
same goes for push
.
you can unwrapp with runState
.
runState pop :: Stack -> (Int, Stack) runState (push 3) :: Stack -> ((), Stack)
if you mean the right-hand side of the >>=
by the "function f
", the f
will be like \a -> pop
or \a -> push 3
, not just pop
.
These 3 things helped me to understand State Monad and the Stack example a little more.
>>=
)The definition of the bind operator in Monad typeclass is this
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
In the Stack example, m
is State Stack
.
If we mentaly replace m
with State Stack
, the definition can be like this.
(>>=) :: State Stack a -> (a -> State Stack b) -> State Stack b
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
.
Here is the example code using do notation in the book.
stackManip :: State Stack Int stackManip = do push 3 pop pop
it can be translated to the following code with bind operator.
stackManip :: State Stack Int stackManip = push 3 >>= \_ -> pop >>= \_ -> pop
Now we can see what will be the right-hand side for the bind operator.
Their types are a -> State Stack b
.
(\_ -> pop) :: a -> State Stack Int (\_ -> push 3) :: a -> State Stack ()
(State s)
and (State h)
in the instance declarationHere is the instance declaration for State in the book.
instance Monad (State s) where return x = State $ \s -> (x,s) (State h) >>= f = State $ \s -> let (a, newState) = h s (State g) = f a in g newState
Considering the types with the Stack example, the type of (State s)
will be
(State s) :: State Stack s :: Stack
And the type of (State h)
will be
(State h) :: State Stack a h :: Stack -> (a, Stack)
(State h)
is the left-hand side argument of the bind operator and its type is State Stack a
as described above.
Then why h
becomes Stack -> (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)
.
newtype State s a = State { runState :: s -> (a,s) }
In general, type of h
is s ->(a, s)
, representation of the stateful computation. Any of followings could be the h
in the Stack example.
runState pop :: Stack -> (Int, Stack) runState (push 3) :: Stack -> ((), Stack) runState stackManip :: Stack -> (Int, Stack)
that's it.