Closed jberryman closed 13 years ago
The problem here is that the instance is ambiguous.
It could be either:
instance (Functor f, Contravariant g) => Contravariant (Compose f g) instance (Contravariant f, Functor g) => Contravariant (Compose f g)
with no good reason to choose one over the other.
Hence the different ComposeFC and ComposeCF data types to allow the developer to disambiguate.
I tend to prefer not to make arbitrary decisions that lock out other perfectly good uses of a type.
For instance, one can make make an Applicative out of a composition of two applicatives or two monads. The applicatives make the most sense and don't really violate the principle of least surprise. But we can make a monad for compose given:
a monad and a pointed functor with a distributive law f (m a) -> m (f a) a monad and a pointed functor with the other distributive law m (f a) -> f (m a) a monad and a pointed functor with a subsumption law: m (n (m a)) -> m (n a)
which should be the instance for Compose?
The instance a Contravariant for Compose is deliberately left out due to this ambiguity, unless we some day get backtracking instance resolution. ;)
Hi Edward, I'm learning a lot looking at your module.
I wonder what you think of this: we treat
Compose
from the transformers package as the composition of a covariant functor with another functor type, and export our ownCompose
type for compositions of contravariant functors with another functor type.This makes sense to me, since users of transformer's
Compose
might be passing around something like:and the above would get nice instances when applied to either a Functor or a Contravariant now.
Brandon