I thought I had a good handle on Haskell Monads until I realized this very simple piece of code made no sense to me (this is from the haskell wiki about the State monad):
playGame :: String -> State GameState GameValue
playGame [] = do
(_, score) <- get
return score
What confuses me is, why is the code allowed to call "get", when the only argument supplied is a string? It seems almost like it is pulling the value out of thin air.
A better way for me to ask the question may be, how would one rewrite this function using >>=
and lambda's instead of do notation? I'm unable to figure it out myself.
Desugaring this into do
notation would look like
playGame [] =
get >>= \ (_, score) ->
return score
We could also just write this with fmap
playGame [] = fmap (\(_, score) -> score) get
playGame [] = fmap snd get
Now the trick is to realize that get
is a value like any other with the type
State s s
What get
will return won't be determined until we feed our computation to runState
or similar where we provide an explicit starting value for our state.
If we simplify this further and get rid of the state monad we'd have
playGame :: String -> (GameState -> (GameState, GameValue))
playGame [] = \gamestate -> (gamestate, snd gamestate)
The state monad is just wrapping around all of this manual passing of GameState
but you can think of get
as accessing the value that our "function" was passed.