The Comonad
concept represents context-sensitive computations and data.
Formally, the Comonad concept is dual to the Monad concept. But unless you're a mathematician, you don't care about that and it's fine. So intuitively, a Comonad represents context sensitive values and computations. First, Comonads make it possible to extract context-sensitive values from their context with extract
. In contrast, Monads make it possible to wrap raw values into a given context with lift
(from Applicative).
Secondly, Comonads make it possible to apply context-sensitive values to functions accepting those, and to return the result as a context-sensitive value using extend
. In contrast, Monads make it possible to apply a monadic value to a function accepting a normal value and returning a monadic value, and to return the result as a monadic value (with chain
).
Finally, Comonads make it possible to wrap a context-sensitive value into an extra layer of context using duplicate
, while Monads make it possible to take a value with an extra layer of context and to strip it with flatten
.
Whereas lift
, chain
and flatten
from Applicative and Monad have signatures
\begin{align*} \mathtt{lift}_M &: T \to M(T) \\ \mathtt{chain} &: M(T) \times (T \to M(U)) \to M(U) \\ \mathtt{flatten} &: M(M(T)) \to M(T) \end{align*}
extract
, extend
and duplicate
from Comonad have signatures
\begin{align*} \mathtt{extract} &: W(T) \to T \\ \mathtt{extend} &: W(T) \times (W(T) \to U) \to W(U) \\ \mathtt{duplicate} &: W(T) \to W(W(T)) \end{align*}
Notice how the "arrows" are reversed. This symmetry is essentially what we mean by Comonad being the dual of Monad.
extract
and (extend
or duplicate
) satisfying the laws below. A Comonad
must also be a Functor
.
For all Comonads w
, the following laws must be satisfied:
Functor
, hence the requirement that a Comonad
also is a Functor
.