Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are monoid and applicative connected?

Tags:

haskell

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?

like image 394
softshipper Avatar asked Jul 10 '17 11:07

softshipper


People also ask

How many methods should a functor instance have?

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.

What is applicative in Haskell?

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.

What is a Monoid Haskell?

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).

Is maybe a functor Haskell?

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).


2 Answers

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

like image 172
Zeta Avatar answered Nov 05 '22 00:11

Zeta


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 Applicatives, 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.

like image 20
Zhiltsoff Igor Avatar answered Nov 05 '22 01:11

Zhiltsoff Igor