Implementing Monoidal in terms of Applicative

后端 未结 1 1076
心在旅途
心在旅途 2021-01-19 21:37

Typeclassopedia presents the following exercise:

Implement pure and (<*>) in terms of unit and (**), and vice versa.

Here\'s

相关标签:
1条回答
  • 2021-01-19 22:15

    Applicative is a neat alternative presentation of Monoidal. Both typeclasses are equivalent, and you can convert between the two without considering a specific data type like Option. The "neat alternative presentation" for Applicative is based on the following two equivalencies

    pure a = fmap (const a) unit
    unit = pure ()
    
    ff <*> fa = fmap (\(f,a) -> f a) $ ff ** fa
    fa ** fb = pure (,) <*> fa <*> fb
    

    The trick to get this "neat alternative presentation" for Applicative is the same as the trick for zipWith - replace explicit types and constructors in the interface with things that the type or constructor can be passed into to recover what the original interface was.

    unit :: f ()
    

    is replaced with pure which we can substitute the type () and the constructor () :: () into to recover unit.

    pure :: a  -> f a
    pure    () :: f ()
    

    And similarly (though not as straightforward) for substituting the type (a,b) and the constructor (,) :: a -> b -> (a,b) into liftA2 to recover **.

    liftA2 :: (a -> b -> c) -> f a -> f b -> f c
    liftA2    (,)           :: f a -> f b -> f (a,b)
    

    Applicative then gets the nice <*> operator by lifting function application ($) :: (a -> b) -> a -> b into the functor.

    (<*>) :: f (a -> b) -> f a -> f b
    (<*>) = liftA2 ($)
    

    Getting from <*> back to liftA2 is common enough that liftA2 is included in Control.Applicative. The <$> is infix fmap.

    liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
    liftA2 f a b = f <$> a <*> b
    
    0 讨论(0)
提交回复
热议问题