From the point of view of category theory, Haskell's type constructors of the kind *->*
define a mapping of objects in the category Hask (it's a category modulo termination issues, which I'm going to conveniently ignore). A functor is a mapping of objects and, more importantly, a mapping of morphisms. In fact, it's primarily a mapping of morphisms--the mapping of objects is, in a way, a side effect of that. Objects are just the endpoints of morphisms. This mapping of morphisms must preserve composition and identity.
In Haskell, morphisms are functions, and the mapping of functions is implemented as fmap
.
The fact that in Haskell we start with the mapping of objects is a little backwards. This works because the syntax of the language drastically limits the possibilities for defining the mapping of objects. Such mapping are very regular and, quite often, come equipped with canonical mappings of functions. For instance, algebraic data types are constructed using products and coproducts, which are functorial in nature (hence the possibility of deriving Functor
automatically). Also, function types (categorical exponentials) are functorial in the second argument (and contravariant in the first). So, as long as we use the tools of the bicartesian closed category (products, coproducts, and exponentials), it's easy to construct functorial mappings of objects.
A functor must be defined for every object in a given category, so data types that are constrained by type classes (e.g., Set
with the Ord
constraint) are not Functor
s in Hask, but they may be functors in a subcategory of Hask. (It's possible to define subcategories in Haskell together with their own functors.)