Reputation: 21985
I was reading about the State monad and after writing the code below I cannot understand how the initial state (mkStdGen 42
) is passed into the rollDice
function?
How can get
work on that initial value?
I understand how the rollDice
function works, but I cannot imagine how the initial state is lifted into the monad.
import Control.Monad.Trans.State
import System.Random
rollDice :: State StdGen Int
rollDice = do
generator <- get
let (x, s) = randomR (1,6) generator
put s
return x
main :: IO ()
main = putStrLn . show $ evalState rollDice (mkStdGen 42)
Upvotes: 1
Views: 214
Reputation: 105925
To keep things simple, think about a State s a
as a function, which takes an initial state s
and returns a value and a new state (a , s)
, just as in the wikibook:
newtype State s a = S { runState :: s -> (s , a) }
Now lets use rollDicePure = runState rollDice
. What's rollDicePure
type? Given that runState
only removes the State
newtype, it should be
rollDicePure :: StdGen -> (Int, StdGen)
So runState
(or evalState
/execState
) simply turn a stateful computation into a simple function, whose argument is the initial state.
If you wonder how get
then gets this state, think of it as
getPure :: s -> (s, s)
getPure st = (st, st)
The actual definitions are a little bit more complicated than that, but the semantics hold.
Upvotes: 4