I am reading in the haskellbook about applicative and trying to understand it.
In the book, the author mentioned:
So, with Applicative, we have a Monoid for our structure and function application for our values!
How is monoid connected to applicative?
According to the implementation, we can map another Functor using two methods: "Pure" and "<*>". The "Pure" method should take a value of any type and it will always return an Applicative Functor of that value.
In Haskell, an applicative is a parametrized type that we think of as being a container for data of that type plus two methods pure and <*> . Consider a parametrized type f a . The pure method for an applicative of type f has type. pure :: a -> f a. and can be thought of as bringing values into the applicative.
From HaskellWiki. In Haskell, the Monoid typeclass (not to be confused with Monad) is a class for types which have a single most natural operation for combining values, together with a value which doesn't do anything when you combine it with others (this is called the identity element).
Another simple example of a functor is the Maybe type. This object can contain a value of a particular type as Just , or it is Nothing (like a null value).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With