Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applicative is to monad what X is to comonad

Can we solve this equation for X ?

Applicative is to monad what X is to comonad

like image 929
nicolas Avatar asked Jan 17 '16 10:01

nicolas


1 Answers

After giving it some thought, I think this is actually a backward question. One might think that ComonadApply is to Comonad what Applicative is to Monad, but that is not the case. But to see this, let us use PureScript's typeclass hierarchy:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

class Functor f => Apply f where
    apply :: f (a -> b) -> f a -> f b -- (<*>)

class Apply f => Applicative f where
    pure :: a -> f a

class Applicative m => Monad m where
    bind :: m a -> (a -> m b) -> m b  -- (>>=)
 -- join :: m (m a) -> m a
 -- join = flip bind id

As you can see, ComonadApply is merely (Apply w, Comonad w) => w. However, Applicative's ability to inject values into the functor with pure is the real difference.

The definition of a Comonad as the categorical dual consists of return's dual extract and bind's dual extend (or the alternative definiton via duplicate as join's dual):

class Functor w => Comonad w where
    extract   :: w a -> a        
    extend    :: (w a -> b) -> w a -> w b
 -- extend f  = fmap f . duplicate k
 -- duplicate :: w a -> w (w a)
 -- duplicate = extend id

So if we look at the step from Applicative to Monad, the logical step between would be a typeclass with pure's dual:

class Apply w => Extract w where
    extract :: w a -> a

class Extract w => Comonad w where
    extend :: (w a -> b) -> w a -> w b

Note that we cannot define extract in terms of extend or duplicate, and neither can we define pure/return in terms of bind or join, so this seems like the "logical" step. apply is mostly irrelevant here; it can be defined for either Extract or Monad, as long as their laws hold:

applyC f = fmap $ extract f   -- Comonad variant; needs only Extract actually (*)
applyM f = bind f . flip fmap -- Monad variant; we need join or bind

So Extract (getting values out) is to Comonad what Applicative (getting values in) is to Monad. Apply is more or less a happy little accident along the way. It would be interesting whether there are types in Hask that have Extract, but not Comonad (or Extend but not Comonad, see below), but I guess those are rather rare.

Note that Extract doesn't exist—yet. But neither did Applicative in the 2010 report. Also, any type that is both an instance of Extract and Applicative automatically is both a Monad and a Comonad, since you can define bind and extend in terms of extract and pure:

bindC :: Extract w => w a -> (a -> w b) -> w b
bindC k f = f $ extract k

extendM :: Applicative w => (w a -> b) -> w a -> w b
extendM f k = pure $ f k    

* Being able to define apply in terms of extract is a sign that class Extend w => Comonad w could be more feasible, but one could have split Monad into class (Applicative f, Bind f) => Monad f and therefore Comonad into (Extend w, Extract w) => Comonad w, so it's more or less splitting hair.

like image 134
Zeta Avatar answered Sep 28 '22 13:09

Zeta