I know what a monad is. I think I have correctly wrapped my mind around what a comonad is. (Or rather, what one is seems simple enough; the tricky part is comprehending what's useful about this...)
My question is: Can something be a monad and a comonad?
I foresee two possible answers:
- Yes, this is common and widely useful.
- No, they do such different jobs that there would be no reason to want something to be both.
So, which is it?
Yes. Turning some comments into an answer:
Reader and Writer are exact duals, as shown by
The Cofree Comonad yields some data structures that are useful as Monads and Comonads both:
Every Cofree Comonad over an Alternative functor yields a Monad -- see the instance here:
http://hackage.haskell.org/packages/archive/free/3.4.1/doc/html/Control-Comonad-Cofree.html
This gives us, e.g. nonempty lists as Monads and Comonads both (along with nonempty f-branching trees, etc).
Identity
is not an alternative, butCofree Identity
yields an infinite stream, and we can in fact give a different monad instance to that stream:http://hackage.haskell.org/packages/archive/streams/3.1/doc/html/Data-Stream-Infinite.html
(note the functions above are not on lists but instead defined in the
streams
package).Similarly the reader arrow is not an alternative, but
Cofree ((->) r)
yields a Moore machine, and Moore machines also are monads and comonads both:http://hackage.haskell.org/packages/archive/machines/0.2.3.1/doc/html/Data-Machine-Moore.html
So what's the intuition behind all these examples? Well we get the comonadic operations for free. The monadic operations we get are all forms of diagonalization. With alternative we can
<|>
things together to "smush" the structure, and magic up "empty" things when we run out of structure to smush. This lets us work on finite cases. Lacking alternative we need to have an indefinite amount of structure, so that no matter how many "join" operations (which we can think of as splicing or substitution) that we make, there's always more room to place the spliced elements (like at the Hilbert Hotel: http://www.encyclopediaofmath.org/index.php/Hilbert_infinite_hotel).Relatedly, every Comonad gives rise to a related Monad (although I consider this more a curiousity):
http://hackage.haskell.org/packages/archive/kan-extensions/3.1.1/doc/html/Control-Monad-Co.html
http://comonad.com/reader/2011/monads-from-comonads/
Expanding on Hammer's suggestion, it seems simple enough to write a function
[x] -> [[x]]
. For example,would work just fine. So it looks like lists could form a comonad. Ah, but wait. That handles
cojoin
, but what aboutcoreturn :: [x] -> x
? This, presumably, is why only non-empty lists form a comonad.This gives us a cobind function with the type
([x] -> x) -> [x] -> [x]
. Interestingly, Hoogle knows of no such function. And yet we already haveconcatMap :: (x -> [x]) -> [x] -> [x]
. I'm not seeing an immediate use for the cobind function, but I can imagine one existing.I'm still trying to wrap my mind around comonad and what it might be useful for. The answers so far have given me something to think about...
It depends on what you consider a "monad" to be. If you ask "is it possible for a type to be an instance of both
Monad
andComonad
at once?" then, yes. Here's a trivial example.If you mean it mathematically, then a monad is a triple
(X, return, bind)
whereX
is a type andreturn
andbind
follow the types and laws you expect. Similarly, a comonad is(X, extend, extract)
. I've just demonstrated that theX
s might be the same, but since the types ofextend
andreturn
orextract
andbind
are different it's not possible for them to be the same functions. So a mathematical monad can never be a comonad.There are many interesting structures that are both a
Monad
and aComonad
.The
Identity
functor has been pointed out here by several other people, but there are non-trivial examples.The
Writer
Monad
plays aReader
-like role as aComonad
.The
Reader
Monad
plays aWriter
-like role as aComonad
.Non-empty lists also form both a monad and a comonad and are in fact a special case of a larger construction involving cofree comonads. The
Identity
case can also be seen as a special case of this.There are also various
Yoneda
andCodensity
-like constructions based on Kan extensions, that work to transform monads and comonads, although they favor one or the other in terms of operational efficiency.I also have an adapter that converts an arbitrary comonad into a monad transformer. Sadly the opposite conversion isn't possible in Haskell.
In linear algebra there is a notion of a bialgebra. Ideally if we have something that forms both a
Monad
and aComonad
and we want to use those operations together without reasoning on a case-by-case basis, one would like to have thatreturn
andjoin
are Comonad coalgebras and by extension thatextract
andduplicate
areMonad
algebras. If those conditions hold then you can actually reason about code that has bothMonad f
andComonad f
constraints and mixes the combinators from each without case-by-case reasoning.