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, Scala)?
It seems there is a fundamental difference in the way Haskell views types as opposed to Scala or C#, and I'd like to articulate what that difference is.
Or maybe I'm wrong and I just haven't learned enough Haskell yet :-)
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.