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

Reply via email to