The next algebraic structure we’ll look at is a functor. In the introduction, we saw that a category consists of objects and arrows. As an example, we morphed a set of strings to another set which contained the reverse of those strings. In other words, we morphed an object to another object. What if we could morph an entire category to another category while preserving the structure? Well, that’s what a functor does.
Formal Definition
Let
Example
Say we have a set
How does this translate to code? This actually translates fairly easily to code. Containers like lists, trees, etc. that you can call map
on are functors.
Let’s write some code. We’ll begin by creating a set
1 | @ val S = Set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Next, we’ll create
1 | @ def f(x: Int) = { x * 2 } |
Next, let’s create
1 | @ val L = List(1, 2, 3) |
Next, we’ll create the function maplist
.
1 | @ def maplist(f: Int => Int)(L: List[Int]) = L map f |
Finally, let’s see this in action:
1 | @ maplist(f)(L) |
As we can see, maplist
applied the function f
on all elements of L
. We did this by using the map
method of a List
instance.
Functor Laws
All functors are expected to obey the two laws that we saw in the formal definition. Let’s see how they translate to code.
First Law
The first law states that if we map the identity function over a functor, we’ll get back a functor which is the same as the original functor.
1 | @ List(1, 2, 3) map identity |
As we can see, applying identity
to the list gives back the same list.
Second Law
The second law states that if we map a functor using a composition of two functions,
We’ll begin by creating two functions f
and g
.
1 | @ def f(x: Int): Int = x + 1 |
Now let’s put the theory into practice.
1 | // composition of two functions |
As we see, the two lists are the same.
More Functor Examples
Example 1
Let’s consider a category where objects are integers. Arrows between objects indicates a “divided by” relationship. For example,
This indicates that 10 can be divided by 5. To reiterate, objects are numbers and arrows represent a “divided by” relationship.
Now let’s create a functor from the category to itself. This functor will multiply each object by 13. So,
The answer is yes. Our category has arrows that indicate a “divided by” relationship. So,
Conclusion
In this post we saw functors which map objects from one category to another. Containers like trees, lists, etc. are functors. All functors are required to obey the two functor laws.