How are monoid and applicative connected?

前端 未结 2 960
醉梦人生
醉梦人生 2021-02-19 03:25

I am reading in the haskellbook about applicative and trying to understand it.

In the book, the author mentioned:

So, with Applicative, we have

相关标签:
2条回答
  • 2021-02-19 04:22

    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

    0 讨论(0)
  • 2021-02-19 04:26

    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.

    0 讨论(0)
提交回复
热议问题