In Haskell/Understanding monads/State there is a snippet code:
type GeneratorState = State StdGen
rollDie :: GeneratorState Int
rollDie = do generator <- get
let (value, newGenerator) = randomR (1,6) generator
put newGenerator
return value
About the Symbol <-
in the above third line, there is an explanation:
we take out the pseudo-random generator with <-
in conjunction with get. get overwrites the monadic value (The a
in m a
) with the state, binding the generator to the state. (If in doubt, recall the definition of get and >>=
above).
I do not understand: (1) generator
is corresponding to the first type parameter of the definition State
? (2) why generator
is just one of the two parameters of State
, not two? Of course, from the context, the answer is obvious, but I do not know the concrete rules about <-
.
To my knowledge, when evaluating evalState rollDie (mkStdGen 600)
, get
will be replaced by State (mkStdGen 0) (mkStdGen 0)
, and, according to RWH's description "<-
pulls things out of monads", things here are not (mkStdGen 0) (mkStdGen 0)
?
I'm not entirely sure about the phrasing of your question, so correct me if I misunderstood.
There is an equivalence between the syntactic sugar for the do-notation syntax <-
and the overloaded bind operator (>>=)
.
do { a <- f ; m } ≡ f >>= \a -> do { m }
So if you were to desugar the binds, it would look like:
rollDie' :: GeneratorState Int
rollDie' =
get >>= \generator ->
let (value, newGenerator) = randomR (1,6) generator in
put newGenerator >>= \_ ->
return value
If you understand how the State monad works, in the implementation it threads around the state in an implicit argument for each bind (i.e. >>=
). A simplified implementation might look like:
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
State act >>= k = State $ \s ->
let (a, s') = act s
in runState (k a) s'
get :: State s s
get = State $ \s -> (s, s)
put :: s -> State s ()
put s = State $ \_ -> ((), s)
So the bind operator when specialized to this specific State monad has the type:
(>>=) :: State s a -> (a -> State s b) -> State s b
The function get
is simply the function that returns the state as an argument so you can inspect it, so it has to match the s
type of the monad it lives in.
-- +--- State
-- | +- Return value (inner state)
-- | |
get :: State s s