(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
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.