I am reading in the haskellbook about applicative and trying to understand it.
In the book, the author mentioned:
So, with Applicative, we have
Remark: I don't own the book (yet), and IIRC, at least one of the authors is active on SO and should be able to answer this question. That being said, the idea behind a monoid (or rather a semigroup) is that you have a way to create another object from two objects in that monoid1:
mappend :: Monoid m => m -> m -> m
So how is Applicative
a monoid? Well, it's a monoid in terms of its structure, as your quote says. That is, we start with an f something
, continue with f anotherthing
, and we get, you've guessed it a f resulthing
:
amappend :: f (a -> b) -> f a -> f b
Before we continue, for a short, a very short time, let's forget that f
has kind * -> *
. What do we end up with?
amappend :: f -> f -> f
That's the "monodial structure" part. And that's the difference between Applicative
and Functor
in Haskell, since with Functor
we don't have that property:
fmap :: (a -> b) -> f a -> f b
-- ^
-- no f here
That's also the reason we get into trouble if we try to use (+)
or other functions with fmap
only: after a single fmap
we're stuck, unless we can somehow apply our new function in that new structure. Which brings us to the second part of your question:
So, with Applicative, we have [...] function application for our values!
Function application is ($)
. And if we have a look at <*>
, we can immediately see that they are similar:
($) :: (a -> b) -> a -> b
(<*>) :: f (a -> b) -> f a -> f b
If we forget the f
in (<*>)
, we just end up with ($)
. So (<*>)
is just function application in the context of our structure:
increase :: Int -> Int
increase x = x + 1
five :: Int
five = 5
increaseA :: Applicative f => f (Int -> Int)
increaseA = pure increase
fiveA :: Applicative f => f Int
fiveA = pure 5
normalIncrease = increase $ five
applicativeIncrease = increaseA <*> fiveA
And that's, I guessed, what the author meant with "function application". We suddenly can take those functions that are hidden away in our structure and apply them on other values in our structure. And due to the monodial nature, we stay in that structure.
That being said, I personally would never call that monodial, since <*>
does not operate on two arguments of the same type, and an applicative is missing the empty element.
1 For a real semigroup/monoid that operation should be associative, but that's not important here
Although this question got a great answer long ago, I would like to add a bit.
Take a look at the following class:
class Functor f => Monoidal f where
unit :: f ()
(**) :: f a -> f b -> f (a, b)
Before explaining why we need some Monoidal
class for a question about Applicative
s, let us first take a look at its laws, abiding by which gives us a monoid:
f a
(x
) is isomorphic to f ((), a)
(unit ** x
), which gives us the left identity. (** unit) :: f a -> f ((), a)
, fmap snd :: f ((), a) -> f a
.f a
(x
) is also isomorphic f (a, ())
(x ** unit
), which gives us the right identity. (unit **) :: f a -> f (a, ())
, fmap fst :: f (a, ()) -> f a
.f ((a, b), c)
((x ** y) ** z
) is isomorphic to f (a, (b, c))
(x ** (y ** z)
), which gives us the associativity. fmap assoc :: f ((a, b), c) -> f (a, (b, c))
, fmap assoc' :: f (a, (b, c)) -> f ((a, b), c)
.As you might have guessed, one can write down Applicative
's methods with Monoidal
's and the other way around:
unit = pure ()
f ** g = (,) <$> f <*> g = liftA2 (,) f g
pure x = const x <$> unit
f <*> g = uncurry id <$> (f ** g)
liftA2 f x y = uncurry f <$> (x ** y)
Moreover, one can prove that Monoidal
and Applicative
laws are telling us the same thing. I asked a question about this a while ago.