15

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?

Julian Leviston
  • 1,646
  • 10
  • 21
softshipper
  • 32,463
  • 51
  • 192
  • 400
  • Great question! You might find [this](https://stackoverflow.com/questions/35013293/what-is-applicative-functor-definition-from-the-category-theory-pov) iluminating. (If not I'll be happy to write up an answer going into a bit more detail.) – Benjamin Hodgson Jul 10 '17 at 11:54
  • 1
    Also: https://stackoverflow.com/questions/13625905/how-much-is-applicative-really-about-applying-rather-than-combining – leftaroundabout Jul 10 '17 at 12:04
  • You might also find typiclassopedia valuable https://wiki.haskell.org/Typeclassopedia#Definition_6 – LudvigH Jul 10 '17 at 12:32
  • 3
    An applicative `m a` has "structure" `m` and "value" `a`. `pure :: a -> m a` gives us the ability to construct a minimal structure (sort of an identity of `m`) and `(<*>) :: m (a -> b) -> m a -> m b` gives us the ability to combine two `m`s (the operation of a monoid) all while defining function application on the values inside (one value is `a -> b`, the other is `a`, and you get back a `b`). – Alec Jul 10 '17 at 15:43
  • 1
    Note that the use of Monoid here is in the more general mathematical sense. Haskell would _not_ accept this as a `Monoid`. – Alec Jul 10 '17 at 16:08

2 Answers2

14

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

Zeta
  • 103,620
  • 13
  • 194
  • 236
  • I've been playing around a bit with another formulation: `class Functor f => Cappl f where unit :: Category c => f (c a a); comp :: Category c => f (c y z) -> f (c x y) -> f (c x z)`. This is equivalent to `Applicative` and also to the seemingly less powerful `class Functor f => Fappl f where funit :: f (a -> a); fcomp :: f (y -> z) -> f (x -> y) -> f (x -> z)`. I dunno if there's anything interesting there. – dfeuer Jul 10 '17 at 20:51
  • @dfeuer Curious: how do you get from `Fappl` to `Cappl` without `Profunctor c`? – Benjamin Hodgson Jul 10 '17 at 21:07
  • @BenjaminHodgson, I actually went `Fappl` to `Applicative` to (obvious) `Cappl` to (trivial) `Fappl`. If you have trouble with that route, let me know. I can give you a hint, but it might be too big. – dfeuer Jul 11 '17 at 01:42
  • @Zeta could you please public the link for irc? – softshipper Jul 11 '17 at 07:21
  • @dfeuer I got it. That hint was big enough – Benjamin Hodgson Jul 11 '17 at 08:29
  • 1
    @zero_coding: IRC? "IIRC" means "If I recall correctly" as in "if I'm not mistaken at least one of the authors has a StackOverflow account". – Zeta Jul 11 '17 at 10:52
1

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.

Zhiltsoff Igor
  • 1,812
  • 8
  • 24