Recall the Applicative
class:
class Functor f => Applicative f where
pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
(<*>) :: f (a -> b) -> f a -> f b
liftA2 h x y = fmap h x <*> y
(<*>) = liftA2 id
Though it's not immediately clear how to express this class in terms of (mathematical) category theory, it becomes clear when the following function is defined:
liftZ2 :: Applicative f => (f a, f b) -> f (a, b)
liftZ2 (x, y) = liftA2 (,) x y
Here, (,)
should be identifiable as the categorical product. Replacing products by coproducts and reversing all the arrows gives the following class:
class Functor f => Coapplicative f where
copure :: f a -> a
coliftZ2 :: f (Either a b) -> Either (f a) (f b)
Some instances:
import Data.Functor.Identity
import qualified Data.List.NonEmpty as NonEmpty
import Data.Either
instance Coapplicative Identity where
copure (Identity x) = x
coliftZ2 (Identity (Left x)) = Left (Identity x)
coliftZ2 (Identity (Right y)) = Right (Identity y)
instance Coapplicative NonEmpty.NonEmpty where
copure (x NonEmpty.:| _) = x
coliftZ2 (Left x NonEmpty.:| xs) = Left (x NonEmpty.:| lefts xs)
coliftZ2 (Right y NonEmpty.:| ys) = Right (y NonEmpty.:| rights ys)
instance Coapplicative ((,) e) where
copure (_, x) = x
coliftZ2 (e, Left x) = Left (e, x)
coliftZ2 (e, Right y) = Right (e, y)
instance Monoid m => Coapplicative ((->) m) where
copure f = f mempty
coliftZ2 f = case copure f of
Left x -> Left (fromLeft x . f)
Right y -> Right (fromRight y . f)
I have a strong intuition that Coapplicative
is a superclass for Comonad
, but I don't know how to prove it. Also, is there a Coapplicative
instance that is not a Comonad
?