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.
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 beingk (runReader m r)
and another beingr
.
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.