This is a tutorial on functors. It is inspired by the already-excellently written article here.
What is a Functor?
In Haskell, there is a Functor type class. If a type is an instance of the Functor class, it is essentially a container type that adds context to any value.
The Functor class is defined as follows:
. That looks a bit weird, so I will rewrite it:
. So, for a container type to be a real Functor, it has to be able to take in a function, and be able to modify the value contained inside itself without changing the context. This is extremely useful. Let’s look at some functors.
The List Functor
Imagine you have a list with some numbers in it:
xs = [1, 2, 3]. Also
imagine you already wrote this function below:
. Now, you’d like to use
makeStatement on the list
xs, which has a
[Int], so that every
Int inside the list gets transformed
makeStatement. Thankfully, List already has an instance
of the Functor class, so we can do it like this:
. Though, since List defines
fmap with a shorter-named
map, we can
map instead of
fmap to save ourselves a keystroke.1
While we’re at it, we might as well drop the
xs because it’s
This is immensely useful. Without the Functor class, you’d have to use
pattern matching to manually extract the values contained in the list
first before applying functions on them. Imagine a sophisticated,
recursive binary tree with millions of elements — as long as the
container type has an instance for Functor, you can just use a
fmap to universally apply the function at hand to every
single element inside the tree (and rest assured that the context for
all the individual values and their interrelationships remain untouched
— a win win!).
For empty lists, You can still pass along a function with
them, but nothing will happen because they are empty (that is, there are
no values inside to modify with the function).
The Maybe Functor
Let’s look at the Maybe type just to prove that they are also functors.
Maybe is a container, except that it can only contain just 1 element
(unlike List which can hold multiple elements). Maybe has two
Nothing; you can use
Just to put a value
into the Maybe type, like how you can use the
(:) function to put
a single item into a list. Alternatively, you can use
denote the empty Maybe container (like
 for lists).
fmap on an empty container will return the empty
The Tuple Functor?
You might be wondering — what about tuples? Well, because tuples hold
different types in a single container, it is impossible to implement
fmap for it. Recall the type signature required for
. Notice that the container must contain a single type
tuples by their nature have arbitrary numbers of different types (they
have apples and oranges in them already). This is the reason why we
don’t (and can’t) have an
fmap function for tuples.
Functors are awesome. If you ever define your own custom container type, be sure to make an instance for Functor to make life easy for everyone.
I imagine other types’
fmapimplementation will have longer names, which would encourage you to just use the universal, 4-letter