Co Monads

What are CoMonads, and what are they good for?


As far as I can tell, a CoMonad? is an object which defines its method =>> such that

    a =>> b :: (w a -> (w a -> b) -> w b) -- w is the comonad type.
This translates (I think, CorrectMe? if I'm wrong) to the more C++ like syntax of
    template<typename A> abstract class CoMonad? {
        template<typename B>
        Functor<CoMonad?<A>, B> operator =>>(CoMonad?<A> a, B b) {
        }
    }
This is in a similar vein as a monad (OnMonads) define their method >>= as
    a >>= b :: (m a -> (a -> m b) -> m b) --m is the monad.
I cannot, however, even hope to understand why they are useful. I don't even know if the above translation is right.


A CoMonad? is a structure with three operations: duplicate :: w a -> w (w a), fmap :: (a -> b) -> w a -> w b and extract :: w a -> a. It is very like a Monad, it is the dual of a Monad.

What does that mean?

Wel a Monad is a structure with three operations: join :: m (m a) -> m a, fmap :: ( a -> b ) -> m a -> m b, return :: a -> m a. As you can see, if you flip the arrows we have the comonad.

So every CoMonad? can be turned into a Monad?

Yes, it can. Just flip the arrows and supply new function definitions.

What is the difference between the two?

Besides the arrows are flipped, monads and comonads have different capabilities. On a concrete level, Monadic action composition is a two stage process:

Monads are always safe to create. eg: Monads are useful for implementing effects.

CoMonadic? action is quite different:

This time there is full access to the structure w, but the action can only extract information from it. The programmer has no control over the information in the structure w. The underlying structure is changed by duplicate.

CoMonads are always safe to destruct. eg: CoMonads are useful for implementing evaluation, iteration.

It is not that different

No, it is not. If we reverse the arrows we go from creation to destruction. From defining side effects to evaluating side effects.


Does comonad<T>(monad<T>(t)) == t?

No, (Co)Monads are Functors. If they are their dual, they will not annihilate their functionalities. Compare the store and the state monad. These are dual to each other, but composed they give some very interesting structure. Namely lenses.


Here is a contribution to the discussion: http://gelisam.blogspot.com/2007/04/i-understand-comonads.html and also this which goes into it in more depth: http://gelisam.blogspot.com/2007/04/of-comonads-and-nightclubs.html

Further inspection of the first of these references gives a different definition from the one [formerly] given above. Note that the final term is w b not just b.

    a =>> b :: (w a -> (w a -> b) -> w b) -- w is the comonad type.
This material leads on to HaskellArrows which can be both monads and comonads.

I am attempting to implement some of this using FC++ (FunctoidsInCpp). -- JohnFletcher


I was working on this some time ago and eventually gave up. I have now returned to it and have been digging around to get some more definitions. One page which I have found which has helped a lot is the following:

http://conal.net/blog/posts/sequences-streams-and-segments

To quote a short section:


The return method injects a pure value into a monadic value (having no effect).

  return  :: Monad m     => a -> m a
The dual to monadic return is extract (sometimes called “counit” or “coreturn“), which extracts a value out of a comonadic value (discarding the value’s context). category-extras library splites this method out from Comonad into the Copointed class:

  extract :: Copointed w => w a -> a
Monadic values are typically produced in effectful computations:

  a -> m b
Comonadic values are typically consumed in context-sensitive computations:

  w a -> b
Monads have a way to extend a monadic producer into one that consumes to an entire monadic value:

  (=<<) :: (Monad m) => (a -> m b) -> (m a -> m b) 
Dually, comonads have a way to extend a comonadic consumer into one that produces an entire comonadic value:

  extend :: (Comonad w) => (w a -> b) -> (w a -> w b)


That for me is a revelation. The last two expressions show the difference between a Monad and a Comonad is the different way in which the operations work. It gives a way to see what needs to be defined for something to be a Comonad.

Example 1

The operations head and tail on a list define a comonad extraction (one element) and extension (a new list without the head).

Example 2

Taking a book from a library is an comonadic extraction process. I have to choose which book. If I take out several I have made a new library as a comonadic extension process.

Taking a book back is monadic. Taking several back is monadic extension.

I hope this helps someone else as much as it has helped me. Comonads are around us all the time, invisibly. -- JohnFletcher


CategoryFunctionalProgramming CategoryHaskell


EditText of this page (last edited December 25, 2012) or FindPage with title or text search