2
votes

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) ?

1

1 Answers

5
votes

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