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.
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe