Alexander Solla ajs at 2piix.com
Thu Aug 26 04:29:16 EDT 2010

```On Aug 26, 2010, at 12:34 AM, michael rice wrote:

> A lot of stuff to get one's head around. Was aware of liftM2,
> liftM3, etc., but not liftA2, liftA3, etc.
>

liftM and liftA are essentially equivalent (and are both essentially
equivalent to fmap)  Same for the liftAn = liftMn functions (where n
is an integer).  Applicative functors are more general than monads, so
it makes sense for them to have their own functions.  It is a matter
of history that liftM was defined before liftA.

> So, the statement was true, but not the way that was shown in the
> example, i.e., with fmap2, fmap3, etc., which required different
> functions for each of the fmaps.

Strictly speaking, fmap will work with a function in more than one
argument, as long as it is properly typed.  This is what makes
applicative functors work.

Consider that a function f :: a -> b -> c also has the type f :: a ->
(b -> c).   If you feed it an "a", (resulting in a value of the form f
a), you get a function g :: (b -> c).  In other words, every function
is a function in one argument.  Some functions just happen to map to
other functions.

<\$> is flip fmap.  f <\$> functor = fmap f functor

Consider what happens if f :: a -> b.  (f <\$> functor) means "pull an
a out of the functor, apply f, and return a functor "over" some b.
That is to say, "lift" f into the functor and apply it.

Now consider what happens if f :: a -> (b -> c).  By analogy, this
means "pull an a out of the functor object, apply f, and return a
functor object (f g)  :: f (b -> c)"  (In other words, a functor
object that "contains" a function g :: b -> c).  In order to get a c
value out of this, you need to apply g to "something".  But note that
we're not just dealing with g.  It is "in" the functor already, and so
doesn't need lifting.  So some smart guy wrote a function called

<*> :: (Functor f) => f (b -> c) -> f b -> f c

that does just that.  This is one of the defining functions for an
applicative functor.  (And part of the reason for the name.  If the
functor contains a function, you can "apply the functor" to properly
typed functor objects.)

The other function is pure :: (a -> b) -> f (a -> b).  It takes a
function and lifts it into the functor, without applying it to
anything.  In other words, given an f :: a -> b,

pure f <*> functor = f <\$> functor

If f has a bigger type (say, a -> b -> c -> d), you can do things like:

f <\$> functor_on_a <*> functor_on_b <*> functor_on_c

Every monad is an applicative functor.  If we have a monad action
m_f :: m (a -> b), and another one m_a :: (m a), we can get a monad
action in type (m b) by pulling the function f :: a -> b out of the
first one and applying it to the b in the second one:

m_f >>= (\f -> liftM f m_a)

or... m_f >>= (flip liftM) m_a

In fact, there is a function called ap :: m (a -> b) -> m a -> m b
which does just that, and is "essentially equivalent" to <*>.  Of
course, running return on a function f is equivalent to running pure
on f.
```