Loading …
link-time Logo
Functors
Functors Functors
Functors
Functors Functors Functors

Functors

As can be imagined after the last article, categories in and of itself are not particularly useful. What's missing is a way to 'link' different categories together, or rather a way to describe relationships between one category and another.

This is where functors come into play:

"Every sufficiently good analogy is yearning to become a functor."

- John Baez

A functor is a mapping between categories with the property, that any property from the domain category will be transfered into the codomain category.

One can also think about functors as a container for data with defined properties.

In our notation that looks as follows:

The Data

Let \(F:\mathcal{C}\rightarrow\mathcal{D}\), it follows

$$A\in\lVert\mathcal{C}\rVert\Rightarrow F(A)\in\lVert\mathcal{D}\rVert$$

"if \(A\) is an object in \(\mathcal{C}\), then \(F(A)\) is an object in \(\mathcal{D}\)"

for all objects in \(\mathcal{C}\) and

$$f\in Morph(\mathcal{C})\Rightarrow F(f)\in Morph(\mathcal{D})$$

"if \(f\) is a morphism in \(\mathcal{C}\), then \(F(f)\) is a morphism in \(\mathcal{D}\)"

for all morphisms in \(\mathcal{C}\).

The properties

The following properties apply to all data of the form \(F(A)\)

$$F(Id_A)=Id_{F(A)}$$

for all identity-morphisms in \(\mathcal{C}\).

Basically this property shall ensure the existance of all identities from the domain category inside the codomain category.

Let then \(f:A\rightarrow B\) and \(g:B\rightarrow C\) be morphisms in \(\mathcal{C}\) and \(\circ_{\mathcal{C}}\) be the composition in \(mathcal{C}\) as well as \(\circ_{\mathcal{D}}\) be the composition in \(\mathcal{D}\) it follows that

$$F(g\circ_{\mathcal{C}}f)=F(g)\circ_{\mathcal{D}}F(f)$$

So if two morphisms in the domain category of \(F\) are composed, it's the same as composing the morphisms mapped with \(F\) in the codomain category.

These two properties are usually referred to as functor-laws.

Commutating diagrams

In category theory morphisms and their compositions are usually pictured as commutating diagrams. These diagrams consisting of objects and arrows enable one to easily spot equivalencies between different compositions.

The commutating diagram for a functor \(F\) looks as follows

Commutating diagram for a functor

It can easily be seen, that 

$$F\circ f\Leftrightarrow F(f)\circ F$$

must apply. For this, we only have to follow the arrow on the right and the one on the bottom (left side of the equation), or alternatively the top arrow followed by the one on the left (right side of the equation).

There is a rule that applies to all commutating diagrams:

If there are multiple paths from one object to another, the compositions of these morphisms must be identical.

Functors in practice

So how do these functors look in practice and which functors may we encounter unknowingly already?

Besides providing a constructor to 'wrap' a value in it, a functor in practice needs to provide a function that allows applying a function to the wrapped value. This function is usually called fmap or map. The only requirement to this function is that the functor laws from above are upheld.

It's type is the following

fmap :: Functor f => (a -> b) -> f a -> f b

So the function takes two parameters; a morphism from a to b, as well as a functor with a value of type a and returns a functor with a value of type b.

Some people may already recall a function that does just that and, yes, lists are functors at least in most modern programming languages. But at least for Kotlin they are not the only functors provided as a standard type. Any? and all its child types are also functors, In their case the map function is implemented with the elvis operator ?. though.

To check up on my claim regarding lists, let's look at them in detail:

  • listOf(x) is the same as \(F(x)\) as it maps the object \(x\) from the category \(\mathcal{X}\) to the object \([x]\) from the category \(\mathcal{L}\).
  • Let l=listOf(1,2,3), and fun f(x: Int) = x+1 it follows l.map(::f)==listOf(2,3,4). So map is equvalent to \(F(f)\) and maps a morphism \(f\) from the category \(\mathcal{X}\) to it's equivalent morphism in \(\mathcal{L}\).
  • Let fun <A> A.id() = this, it follows listOf(1,2).id()==listOf(1.id(),2.id()).
  • Let fun <A,B,C> compose(f: (A)->B, g: (B)->C): (A)->C = {input -> g(f(input))}, and let   fun f(x: Int) = x+1 as well as fun g(x: Int) = x*3. It follows listOf(1,2).map(compose(f,g))==listOf(compose(f,g)(1),compose(f,g)(2))

With that all the requirements for a functor are satisfied and thus, lists are functors.


Patrick Louis

Patrick Louis

› github.com/p-louis

› Show all articles

Your browser is out-of-date!

Update your browser to view this website correctly. Update your browser now!

×