C. McCann cam at uptoisomorphism.net
Fri Dec 24 03:56:39 CET 2010

```On Thu, Dec 23, 2010 at 5:25 PM, Stephen Tetley
<stephen.tetley at gmail.com> wrote:
> On 23 December 2010 21:43, Mario Blažević <mblazevic at stilo.com> wrote:
>> Why are Cofunctor and Comonad classes not a part of the base library?
> [SNIP]
>> Later on I found that this question has been raised before by Conal Elliott,
>> nearly four years ago.
>>
>
> From a somewhat "philistine" persepective, that Conal's question went
>
> "Does anyone have useful functionality to go into a Cofunctor module
> (beyond the class declaration)?"
>
> Successful post-H98 additions to Base (Applicative, Arrows, ...)
> brought a compelling programming style with them. For Comonads,
> Category-extras does define some extra combinators but otherwise they
> have perhaps seemed uncompelling.

As it happens, there actually is a significant programming style to go
with "cofunctors". There's also a reason why it may not seem
compelling to Haskell programmers, which I will illustrate with an
analogy to other programming languages:

Consider the problem of variance in a language with a subtyping
relation and optionally mutable references. A subtype relationship A
<: B can be viewed as an implicit conversion operator from A to B.
Therefore, if you have a read-only reference to something of type A,
you can create a read-only reference to something of type B. This can
be seen as analogous to mapping the implicit conversion function over
the identity functor applied to type A.

On the other hand, what if you have a mutable reference to something
of type A? You can't assign something of type B to it, because
anything reading from the reference will receive a B, and there's no
implicit conversion from B to A. However, if you instead have a
mutable reference to something of type B, you can indeed assign
something of type A to it using the implicit conversion. This is
likewise analogous to mapping the conversion over an identity
"cofunctor".

In other words, contravariant functors naturally describe concepts
like destructive assignment, pushing values into a "data sink" of some
sort, etc.

The simplest example of a potential contravariant functor in Haskell
would be (-> r), i.e., a flipped version of the basic Reader functor
(e ->).

Similarly, assigning to an IORef, partially applied to the reference
itself, gives the type (a -> IO ()), which is a special case of the