I know what covariance and contravariance of types are. My question is why haven\'t I encountered discussion of these concepts yet in my study of Haskell (as opposed to, say
As mentioned, Haskell does not have subtypes. However, if you're looking at typeclasses it may not be clear how that works without subtyping.
Typeclasses specify predicates on types, not types themselves. So when a Typeclass has a superclass (e.g. Eq a => Ord a), that doesn't mean instances are subtypes, because only the predicates are inherited, not the types themselves.
Also, co-, contra-, and in- variance mean different things in different fields of math (see Wikipedia). For example the terms covariant and contravariant are used in functors (which in turn are used in Haskell), but the terms mean something completely different. The term invariant can be used in a lot of places.
There are two main reasons:
However, the concepts do apply--for instance, the lifting operation performed by fmap
for Functor
instances is actually covariant; the terms co-/contravariance are used in Category Theory to talk about functors. The contravariant package defines a type class for contravariant functors, and if you look at the instance list you'll see why I said it's much less common.
There are also places where the idea shows up implicitly, in how manual conversions work--the various numeric type classes define conversions to and from basic types like Integer
and Rational
, and the module Data.List
contains generic versions of some standard functions. If you look at the types of these generic versions you'll see that Integral
constraints (giving toInteger
) are used on types in contravariant position, while Num
constraints (giving fromInteger
) are used for covariant position.
There are no "sub-types" in Haskell, so covariance and contravariance don't make any sense.
In Scala, you have e.g. Option[+A]
with the subclasses Some[+A]
and None
. You have to provide the covariance annotations +
to say that an Option[Foo]
is an Option[Bar]
if Foo extends Bar
. Because of the presence of sub-types, this is necessary.
In Haskell, there are no sub-types. The equivalent of Option
in Haskell, called Maybe
, has this definition:
data Maybe a = Nothing | Just a
The type variable a
can only ever be one type, so no further information about it is necessary.