Studying functors, applicative functors and monads in Haskell, I found this definition on Wikipedia:
In functional programming, specifically Haskell, an applicative
functor is a structure that is like a monad (return
, fmap
, join
)
without join
, or like a functor with return
.
I can't understand: it seems to me that providing return
(i.e. pure
) to a functor is not sufficient to obtain an applicative functor, because you need to provide ap
(i.e. <*>
) too, which cannot be defined in terms of fmap
and return
only. Did I miss something or Wikipedia's definition is not absolutely correct?
EDIT 2017-02-08: I found other useful insights on this question in this answer.
The article was not correct. Assume we have a monad m
without join
, or a functor with return
. We can define pure
immediately:
pure :: Monad m => a -> m a
pure = return
We cannot, however, define (<*>)
with fmap
and return
only. All we have is fmap
, so we would end up with m (m a)
if we try to use an m (a -> b)
. At that point we need join
or its equivalent (>>=)
:
(<*>) :: Monad m => m (a -> b) -> m a -> m b
f <*> x = join (fmap (flip fmap x) f)
-- or, easier to read:
-- f <*> x = do
-- f' <- f
-- x' <- x
-- return f' x'
An applicative functor is like a functor with return
and ap
, but no join
. So yes, you were completely right, Wikipedia missed the operation of applicative (see the original paper).
By the way, if you add only pure
, you get a pointed functor. The typeclassopedia provides a better overview over Applicative
than the Wikipedia article, though.
You are correct, applicative functors require <*>
as well as pure
for a minimal definition. It's worth noting that we can get fmap
from those, though:
fmap f a = pure f <*> a
Similarly we can get the applicative definition from monads:
pure = return
f' <*> a' = do
f <- f'
a <- a'
return $ f a
You could look at applicatives functors a generalization of functors to multi argument functions or as combining values with context horizontally:
liftA2 f a b = f <$> a <*> b
fmap :: (a -> b) -> (f a -> f b)
liftA2 :: (a -> b -> c) -> (f a -> f b -> f c)