
Why are Cofunctor and Comonad classes not a part of the base library? I recently defined a data type (Control.Cofunctor.Ticker in monad-coroutine on Hackage) that happens to be a co-functor, or contra-functor if you prefer. In other words, it can implement the following function:
cofmap :: (a -> b) -> cf b -> cf a
I wanted to define a proper instance for it, but to my surprise I discovered that I couldn't. Not only is the class not defined in base, the only package I could find on Hackage that defines it is category-extras. This is a huge package I'd rather not have as a dependency, so I opted not to declare any instance. Later on I found that this question has been raised before by *Conal Elliott*, nearly four years ago. http://www.haskell.org/pipermail/libraries/2007-January/006740.html The result was the TypeCompose package, which presents a decent solution. I still can't think of any harm in having a proper class declaration in the base library: if you don't need it, you don't need to know it. But without the class declaration in the base library (or in some other obvious package) every other released library must either lack the instance declarations or declare the class itself and risk clashes. This is not some obscure class you've never encountered, by the way: any "consumer" of data is a cofunctor. All regexp data types, for example, are cofunctor instances - or would be if there was a class to declare them instances of. The same question extends to Comonad. I am not too familiar with this area so there may be fewer potential instances of the class, but I remember there was quite a bit of buzz around comonads a few years ago. Judging by a cursory Hayoo search, if anything the situation is worse than with Cofunctor: there are multiple incompatible declarations of the class scattered in various libraries that need it: ad, category-extras, data-category, rope. There is also evidence of undeclared Comonad instances: see the ListZipper and value-supply libraries. So, is it time to add these two classes to the base library?

On 23 December 2010 21:43, Mario Blažević
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.
http://www.haskell.org/pipermail/libraries/2007-January/006740.html
From a somewhat "philistine" persepective, that Conal's question went unanswered says something:
"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.

On Thu, Dec 23, 2010 at 5:25 PM, Stephen Tetley
On 23 December 2010 21:43, Mario Blažević
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.
http://www.haskell.org/pipermail/libraries/2007-January/006740.html
From a somewhat "philistine" persepective, that Conal's question went unanswered says something:
"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.
There are plenty of potential Cofunctor instances on Hackage, as I've pointed out. The other side of the proof of the utility of the class would be to find existing libraries that could be parameterized by an arbitrary functor: in other words, some examples in Hackage of
class Cofunctor c => ... instance Cofunctor c => ... f :: Cofunctor c => ...
This would be rather difficult to prove - such signatures cannot be declared today, and deciding if existing declarations could be generalized in this way would require a pretty deep analysis. The only thing I can say is "build it and they will come". To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?

For me, mostly naming. Cofunctor isn't the right name for it, and comap,
while short, feels wrong. Contrafunctor feels better but is also cumbersome.
No problems with Comonad, though.
On Thu, Dec 23, 2010 at 9:16 PM, Mario Blažević
On Thu, Dec 23, 2010 at 5:25 PM, Stephen Tetley
wrote: On 23 December 2010 21:43, Mario Blažević
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.
http://www.haskell.org/pipermail/libraries/2007-January/006740.html
From a somewhat "philistine" persepective, that Conal's question went unanswered says something:
"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.
There are plenty of potential Cofunctor instances on Hackage, as I've pointed out. The other side of the proof of the utility of the class would be to find existing libraries that could be parameterized by an arbitrary functor: in other words, some examples in Hackage of
class Cofunctor c => ... instance Cofunctor c => ... f :: Cofunctor c => ...
This would be rather difficult to prove - such signatures cannot be declared today, and deciding if existing declarations could be generalized in this way would require a pretty deep analysis. The only thing I can say is "build it and they will come".
To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 12/23/10 9:41 PM, Daniel Peebles wrote:
For me, mostly naming. Cofunctor isn't the right name for it, and comap, while short, feels wrong. Contrafunctor feels better but is also cumbersome. No problems with Comonad, though.
It is wrong. Cofunctors are exactly functors. It's unfortunate that "contramap" is such a long name though. -- Live well, ~wren

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 ...regardless of the utility of a contravariant functor type-class, I strongly advocate for calling it Contrafunctor and not Cofunctor. I have seen numerous examples of confusion over this, particularly in other languages. On 24/12/10 12:16, Mario Blažević wrote:
On Thu, Dec 23, 2010 at 5:25 PM, Stephen Tetley
mailto:stephen.tetley@gmail.com> wrote: Why are Cofunctor and Comonad classes not a part of the base
On 23 December 2010 21:43, Mario Blažević
mailto:mblazevic@stilo.com> wrote: library? [SNIP] Later on I found that this question has been raised before by Conal Elliott, nearly four years ago.
http://www.haskell.org/pipermail/libraries/2007-January/006740.html
- From a somewhat "philistine" persepective, that Conal's question
went unanswered says something:
"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.
There are plenty of potential Cofunctor instances on Hackage, as I've pointed out. The other side of the proof of the utility of the class would be to find existing libraries that could be parameterized by an arbitrary functor: in other words, some examples in Hackage of
class Cofunctor c => ... instance Cofunctor c => ... f :: Cofunctor c => ...
This would be rather difficult to prove - such signatures cannot be declared today, and deciding if existing declarations could be generalized in this way would require a pretty deep analysis. The only thing I can say is "build it and they will come".
To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
- -- Tony Morris http://tmorris.net/ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk0UIJ0ACgkQmnpgrYe6r62kWgCeNwZnYLetOFevK6bpCBE/joKO 2QQAniaX4IGzAmdjEC8kdDV27upUTsBw =NP27 -----END PGP SIGNATURE-----

On 24 December 2010 02:16, Mario Blažević
To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
Hi Mario For the record I'm personally neutral on Cofunctor and on balance would like to see Comonad added to Base. My reservation is really at the "meta-level" - I suspect there are a lot of candidates for adding to Base if you want to Base to be systematic about "modeling structures". At the moment and possibly by accident rather than explicit intention, the structures in Base (Monoid, Applicative, Monad, Arrow) add good sets of operational combinators as well as modeling structures (in Monoid's case it only adds one operational combinator but it is the basis for Foldable, the Writer Monad and more). For Comonad, Cofunctor (Bifunctor, Semigroup...) not having the visibility of being in Base certainly means there is less motivation to discover valuable operations that use them, but should they go into Base without an initial strong operational value, instead maybe something between Base and Hackage is needed? Certainly, Hackage isn't great for developing "Base candidates". The bike shedding on the Libraries list, whilst frustrating for a proposer, is valuable for teasing out more regular designs than single authored packages often manage, and having lots of small packages for Base-like things is a dependency burden that hinders adoption. Best wishes Stephen

+1 for adding a Contrafunctor/ContraFunctor to base somewhere. But I agree
completely with Tony, please call it contramap. ;) Otherwise people will
wonder why comonads are not cofunctors -- a matter which can be cleared up
by avoiding sloppy terminology.
+1 for adding Comonads. As an aside, since Haskell doesn't have (nor could
it have) coexponential objects, there is no 'missing' Coapplicative concept
that goes with it, so there can be no objection on the grounds of lack of
symmetry even if the Functor => Applicative => Monad proposal goes through.
I have been meaning to split off a 'comonads' package from category-extras
for a while, in a way that avoids requiring tons of crazy machinery. I have
a candidate that I just need to polish up a bit and throw on hackage --
perhaps that could serve as a straw man proposal?
-Edward
On Fri, Dec 24, 2010 at 4:51 AM, Stephen Tetley
On 24 December 2010 02:16, Mario Blažević
wrote: To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
Hi Mario
For the record I'm personally neutral on Cofunctor and on balance would like to see Comonad added to Base.
My reservation is really at the "meta-level" - I suspect there are a lot of candidates for adding to Base if you want to Base to be systematic about "modeling structures". At the moment and possibly by accident rather than explicit intention, the structures in Base (Monoid, Applicative, Monad, Arrow) add good sets of operational combinators as well as modeling structures (in Monoid's case it only adds one operational combinator but it is the basis for Foldable, the Writer Monad and more).
For Comonad, Cofunctor (Bifunctor, Semigroup...) not having the visibility of being in Base certainly means there is less motivation to discover valuable operations that use them, but should they go into Base without an initial strong operational value, instead maybe something between Base and Hackage is needed?
Certainly, Hackage isn't great for developing "Base candidates". The bike shedding on the Libraries list, whilst frustrating for a proposer, is valuable for teasing out more regular designs than single authored packages often manage, and having lots of small packages for Base-like things is a dependency burden that hinders adoption.
Best wishes
Stephen
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, 2010-12-24 at 05:36 -0500, Edward Kmett wrote:
+1 for adding Comonads. As an aside, since Haskell doesn't have (nor could it have) coexponential objects, there is no 'missing' Coapplicative concept that goes with it, so there can be no objection on the grounds of lack of symmetry even if the Functor => Applicative => Monad proposal goes through.
There is still potentially useful Copointed/CoPointed: class [Functor a =>] CoPointed a where copoint :: f a -> a Regards

On Fri, Dec 24, 2010 at 7:43 AM, Maciej Piechotka
On Fri, 2010-12-24 at 05:36 -0500, Edward Kmett wrote:
+1 for adding Comonads. As an aside, since Haskell doesn't have (nor could it have) coexponential objects, there is no 'missing' Coapplicative concept that goes with it, so there can be no objection on the grounds of lack of symmetry even if the Functor => Applicative => Monad proposal goes through.
There is still potentially useful Copointed/CoPointed:
class [Functor a =>] CoPointed a where copoint :: f a -> a
Why should Copointed, or Pointed for that matter, be a subclass of Functor? I don't see the point of arranging all possible classes into a single complete hierarchy. These single-method classes can stand on their own. Once you have them, it's easy to declare
class (Functor f, Pointed f) => Applicative f
and also
class (Foldable f, Pointed f) => Sequence f
or whatever.
On Fri, Dec 24, 2010 at 4:51 AM, Stephen Tetley
On 24 December 2010 02:16, Mario Blažević
wrote: To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
Hi Mario
For the record I'm personally neutral on Cofunctor and on balance would like to see Comonad added to Base.
My reservation is really at the "meta-level" - I suspect there are a lot of candidates for adding to Base if you want to Base to be systematic about "modeling structures".
There is a limited number of methods with up to N unconstrained arguments, combinatorics takes care of that. class Foo (x :: *) where method1 :: x -- default, mempty, minBound, maxBound method2 :: x -> x -- succ, pred, negate method3 :: x -> x -> x -- mappend method4 :: (x -> x) -> x -- fix class Cons (c :: * -> *) where method1 :: x -> c x -- return, pure method2 :: c x -> x -- extract method3 :: c (c x) -> c x -- join method4 :: c x -> c (c x) -- duplicate method5 :: c (c x) -> x method6 :: x -> c (c x) method7 :: x -> c x -> c x method8 :: c x -> c x -> x method9 :: (x -> x) -> c x -> c x method10 :: (x -> y) -> c x -> c y -- fmap method11 :: (x -> y) -> c y -> c x -- contramap method12 :: x -> c y -> c y method13 :: x -> c y -> c x method14 :: c x -> c y -> x method15 :: c x -> (x -> c x) -> c x method16 :: c x -> (x -> c y) -> c y -- >>= method17 :: c x -> (c x -> x) -> c x method18 :: c x -> (c x -> y) -> c y -- extend I may have left something out, but all types above should be inhabited. I have omitted methods on constructors that can be defined on a plain type, such as mplus :: m a -> m a -> m a, which is a restriction of the type of mappend. If one were to explore the design space systematically with no backward compatibility baggage, the best approach might be: - declare each method in a class of its own, with no laws whatsoever, - never declare two methods in a same class, - combine the primitive classes into bigger classes, - restrict the bigger classes with laws. The Pointed and Copointed classes above are two examples.

I remember seeing this very discussion about pointed being disjoint from
functor just recently on one of the various haskell mailing lists. But as
for my opinion on it, because there's no real way of specifying any laws for
pointed without functor. With functor and pointed, you can say that you
expect fmap f . point == point . f, but point on its own gives you nothing
to latch onto for behavior expectations.
On Fri, Dec 24, 2010 at 11:08 AM, Mario Blažević
On Fri, Dec 24, 2010 at 7:43 AM, Maciej Piechotka
wrote: On Fri, 2010-12-24 at 05:36 -0500, Edward Kmett wrote:
+1 for adding Comonads. As an aside, since Haskell doesn't have (nor could it have) coexponential objects, there is no 'missing' Coapplicative concept that goes with it, so there can be no objection on the grounds of lack of symmetry even if the Functor => Applicative => Monad proposal goes through.
There is still potentially useful Copointed/CoPointed:
class [Functor a =>] CoPointed a where copoint :: f a -> a
Why should Copointed, or Pointed for that matter, be a subclass of Functor? I don't see the point of arranging all possible classes into a single complete hierarchy. These single-method classes can stand on their own. Once you have them, it's easy to declare
class (Functor f, Pointed f) => Applicative f
and also
class (Foldable f, Pointed f) => Sequence f
or whatever.
On Fri, Dec 24, 2010 at 4:51 AM, Stephen Tetley
wrote: On 24 December 2010 02:16, Mario Blažević
wrote: To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
Hi Mario
For the record I'm personally neutral on Cofunctor and on balance would like to see Comonad added to Base.
My reservation is really at the "meta-level" - I suspect there are a lot of candidates for adding to Base if you want to Base to be systematic about "modeling structures".
There is a limited number of methods with up to N unconstrained arguments, combinatorics takes care of that.
class Foo (x :: *) where method1 :: x -- default, mempty, minBound, maxBound method2 :: x -> x -- succ, pred, negate method3 :: x -> x -> x -- mappend method4 :: (x -> x) -> x -- fix
class Cons (c :: * -> *) where method1 :: x -> c x -- return, pure method2 :: c x -> x -- extract method3 :: c (c x) -> c x -- join method4 :: c x -> c (c x) -- duplicate method5 :: c (c x) -> x method6 :: x -> c (c x) method7 :: x -> c x -> c x method8 :: c x -> c x -> x method9 :: (x -> x) -> c x -> c x method10 :: (x -> y) -> c x -> c y -- fmap method11 :: (x -> y) -> c y -> c x -- contramap method12 :: x -> c y -> c y method13 :: x -> c y -> c x method14 :: c x -> c y -> x method15 :: c x -> (x -> c x) -> c x method16 :: c x -> (x -> c y) -> c y -- >>= method17 :: c x -> (c x -> x) -> c x method18 :: c x -> (c x -> y) -> c y -- extend
I may have left something out, but all types above should be inhabited. I have omitted methods on constructors that can be defined on a plain type, such as mplus :: m a -> m a -> m a, which is a restriction of the type of mappend.
If one were to explore the design space systematically with no backward compatibility baggage, the best approach might be:
- declare each method in a class of its own, with no laws whatsoever, - never declare two methods in a same class, - combine the primitive classes into bigger classes, - restrict the bigger classes with laws.
The Pointed and Copointed classes above are two examples.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, Dec 24, 2010 at 5:36 AM, Edward Kmett
+1 for adding a Contrafunctor/ContraFunctor to base somewhere. But I agree completely with Tony, please call it contramap. ;) Otherwise people will wonder why comonads are not cofunctors -- a matter which can be cleared up by avoiding sloppy terminology.
+1 for adding Comonads. As an aside, since Haskell doesn't have (nor could it have) coexponential objects, there is no 'missing' Coapplicative concept that goes with it, so there can be no objection on the grounds of lack of symmetry even if the Functor => Applicative => Monad proposal goes through.
I have been meaning to split off a 'comonads' package from category-extras for a while, in a way that avoids requiring tons of crazy machinery. I have a candidate that I just need to polish up a bit and throw on hackage -- perhaps that could serve as a straw man proposal?
Yes, please. The interface of Comonad is big enough to require some proper design, and an exclusive comonads package would be a good place for refining it. The same arguments can be made for ContraFunctor, though in this case the only open questions are only the naming of the module, class and its single method, and what instances to declare inside the module.
-Edward
On Fri, Dec 24, 2010 at 4:51 AM, Stephen Tetley
wrote: On 24 December 2010 02:16, Mario Blažević
wrote: To turn the proof obligation around, what could possibly be the downside of adding a puny Cofunctor class to the base library?
Hi Mario
For the record I'm personally neutral on Cofunctor and on balance would like to see Comonad added to Base.
My reservation is really at the "meta-level" - I suspect there are a lot of candidates for adding to Base if you want to Base to be systematic about "modeling structures". At the moment and possibly by accident rather than explicit intention, the structures in Base (Monoid, Applicative, Monad, Arrow) add good sets of operational combinators as well as modeling structures (in Monoid's case it only adds one operational combinator but it is the basis for Foldable, the Writer Monad and more).
For Comonad, Cofunctor (Bifunctor, Semigroup...) not having the visibility of being in Base certainly means there is less motivation to discover valuable operations that use them, but should they go into Base without an initial strong operational value, instead maybe something between Base and Hackage is needed?
Certainly, Hackage isn't great for developing "Base candidates". The bike shedding on the Libraries list, whilst frustrating for a proposer, is valuable for teasing out more regular designs than single authored packages often manage, and having lots of small packages for Base-like things is a dependency burden that hinders adoption.
Best wishes
Stephen
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Dec 23, 2010 at 5:25 PM, Stephen Tetley
On 23 December 2010 21:43, Mario Blažević
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.
http://www.haskell.org/pipermail/libraries/2007-January/006740.html
From a somewhat "philistine" persepective, that Conal's question went unanswered says something:
"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 flipped Reader. - C.

On 12/23/10 16:43, Mario Blažević wrote:
Cofunctor and Comonad
IMHO, as you say, there is only one design of cofunctor. class Cofunctor cf where cofmap :: (a -> b) -> cf b -> cf a The only question is capitalization and spelling.* Since there are multiple designs of Comonad floating around, it'll take slightly more design work to make sure a standard design works for everyone. -Isaac *(CoFunctor or Cofunctor, cofmap or comap etc. IMHO your choices are fine. And to choose a module to put it in.).
participants (9)
-
C. McCann
-
Daniel Peebles
-
Edward Kmett
-
Isaac Dupree
-
Maciej Piechotka
-
Mario Blažević
-
Stephen Tetley
-
Tony Morris
-
wren ng thornton