Thu Nov 25 07:40:52 EST 2010

```Paul Sargent <psarge at gmail.com> writes:

> Digging a little deeper, I decided to look at the definition of ap:
>
>     ap =  liftM2 id
>
>     liftM2  :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
>     liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }
>
> liftM2 makes sense to me, but again we seem to have a mismatch of types. liftM2 wants a two argument function for it's first argument, but ap provides id. I'm finding myself tumbling further and further down the rabbit hole.
>

id has type a -> a, so if you "instantiate" a to `a2 -> r', you get:

id :: (a2 -> r) -> (a2 -> r)

Since -> is right-associative this is the same as:

id :: (a2 -> r) -> a2 -> r

So that's how id can be seen as a two-argument function in this
case. That results in liftM2 id having the type:

liftM2 id :: (Monad m) => m (a2 -> r) -> m a2 -> m r

liftM2 id :: (s -> a2 -> r) -> (s -> a2) -> (s -> r)

So appying (liftM2 id), which is ap, to (+), causes s, a2 and r to be
the same type, since (+) has type (Num a) => a -> a -> a.

liftM2 id (+) :: Num a => (a -> a) -> a -> a

If you then apply that to id, as in ap (+) id, you get:

ap (+) id = liftM2 id (+) id :: Num a => a -> a

So this explains the type, and if you then expand the definitions of
liftM2 and >>= and return for the Reader monad, you will see that this
corresponds to \x -> x + x.

Regards,
Daniel

```