(Covariant) Functor

Initually, functor is a mapping from one category to another, which preserves the structure of the origin one.

Formally, functor is defined as

A functor $F:C→D$ between categories $C$ and $D$ is a mapping of objects to objects and arrows to arrows, in such a way that:

  • $F(f:A→B)=F(f):F(A)→F(B)$
  • $F(g\cdot f)=F(g)\cdot F(f)$
  • $F(1_A)=1_{F(A)}$

In Haskell:

class Functor f where
    fmap  (a b) f a f b

Contravariant1 Functor

A contravariant functor is like a functor but it reverses the directions of the morphisms. —— nLab

Basically it's the "reversed" version of covariant functor.

In Haskell:

class Contravariant f where
    contramap  (b a) f a f b

Bi(nary )Functor

Bifunctor is a functor which domain is the product of two categories.

ie.

For $C_1$, $C_2$ and $D$ categories, a functor $F:C_1\times C_2→D$ is a bifunctor.

class Bifunctor f where
    bimap  (a c)  (b d) f a b f c d

Examples of bifunctor include Either and (,).

instance Bifunctor (,) where
    bimap f g (x , y) = (f x , g y)

instance Bifunctor Either where
    bimap f g = either (Left . f) (Right . g)

Profunctor

A Profunctor is just a bifunctor that is contravariant in the first argument and covariant in the second. What's the problem? —— School of Haskell

So we just "reverse" the first argument of Bifunctor:

class Profunctor f where
    dimap  (c a)  (b d) f a b f c d

A good example of profunctor is (->):

instance Profunctor (->) where 
    dimap ca bd ab = bd . ab . ca
1

If you are familiar with "tradition" programming languages like Java or C#, you may have heard of "covariant" and "contravariant" before. For example, if type A is subtype of B, then IEnumerable<A> is subtype of IEnumerable<B>, so IEnumerable<T> is covariant on T. And similarly, Action<T> is contravariant on T. We can regard covariant and contravariant functors as more abstract (we weaken relationship from subtype to arbitrary binary relation) version of these types.