Search code examples
haskellmonadsreader-monad

Implementing the Reader monad (from Real World Haskell book)


newtype Reader e a = R { runReader :: e -> a }

instance Monad (Reader e) where 
  return a = R $ \_ -> a
  m >>= k  = R $ \r -> runReader (k (runReader m r)) r

I am having difficulty understanding these two snippets. I can tell that the first one is a record syntax description of a reader that has a function runReader from e to a, but the second one puzzles me.

By binding m with k, it's essentially trying to create a new Reader, but how does

runReader (k (runReader m r)) r

work out? I thought runReader only takes one argument, but it seems it's taking two right now, one being k (runReader m r) and another being r.

Thanks in advance.


Solution

  • I am having difficulty understanding the Reader Monad.

    Edit: I should point to a number of resources on this, rather than attempt to repeat them.

    I thought runReader only takes one argument, but it seems it's taking two right now, one being k (runReader m r) and another being r.

    If you look at the type signature for runReader :: Reader e a -> e -> a, this can be seen as either taking a Reader e a and producing an e -> a, or as taking a Reader e a and an e and producing an a. The point of the reader monad is to introduce an implicit argument.

    How does runReader (k (runReader m r)) r work out?

    You could spell out the bind operator definition a little more:

    instance Monad (Reader e) where 
      return a = R $ \_ -> a
      -- (>>=) :: Reader e a -> (a -> Reader e b) -> Reader e b
      ma >>= k = R $ \e -> let a = runReader ma e
                               mb = k a
                           in runReader mb e
    

    That is, first "ma is run with e" (runReader ma :: e -> a is applied to e). This produces an a.

    Then k a is run. This produces an mb.

    Then "mb is run with e" (runReader mb :: e -> b is applied to e).

    This is packaged up into R $ \e -> ... runReader mb e.

    I've come to the thought that the difficult part of understanding this is mostly tied to the way newtype requires constant wrapping (R) and unwrapping (runReader) of its content, rather than the notorious how monads work.


    Imagine the only monad you ever needed was the reader monad, and we could do without the newtype and instance Monad (Reader e) fluff. Then your definition could look like:

    type Reader e a = e -> a
    -- type Reader e a = (->) e a
    -- type Reader e = (->) e
    
    unit :: a -> Reader e a
    --   :: a -> (e -> a)
    unit a = \_e -> a
    -- unit a _e = a
    -- unit = const
    
    ask :: Reader e e
    --  :: e -> e
    ask = \e -> e
    -- ask e = e
    -- ask = id
    
    bind :: Reader e a -> (a -> Reader e b) -> Reader e b
    --   :: (e -> a)   -> (a -> (e -> b))   -> (e -> b)
    bind ma k = \e -> let a = ma e
                          mb = k a
                      in mb e
    -- bind ma k e = let mb = k (ma e) in mb e
    

    at which point it becomes more clear that all unit does is discard e, all ask does is return e, and what bind does is take two functions (ma and k (ma e), aka mb) that both expect an e, composes them inside a new function that also expects an e, without having to explicitly pass e during the composition.

    A misconception I had myself when learning how to write monad definitions was that runReader runs anything. It helped me conceptually to call it unR since all it does is remove the R wrapping.