Search code examples
haskellmonadsstate-monad

Why can I call a monadic function without supplying a monad?


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.


Solution

  • 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.