From this chapter on, we will change the tactic a bit (as I am sure you are tired of jumping through different subjects) and we will dive at full throttle into the world of categories, using the structures that we saw so far as context. This will allow us to generalize some of the concepts that we examined in these structures and thus make them valid for all categories.
We also learned about some *special types of categories* each of which has some distinct properties, like categories that have just one *object* (monoids, groups) and categories that have only one *morphism* between any two objects (preorders, partial orders.)
We also defined a lot of *categories based on different concepts*, like the ones based on logics/programming languages, but also some "less-serious ones", as for example the color-mixing partial order/category.
And most importantly, we saw some categories that are *completely made up*, such as my soccer player hierarchy. Those are formally called *finite categories*.
Although they are not useful by themselves, the idea behind them is important - we can draw any combination of points and arrows and call it a category, in the same way that we can construct a set out of every combination of objects.
If we increment the number of objects to two, we see a couple of more interesting categories, like for example the category $2$ containing two objects and one morphism.
Many of the categories that we saw are similar to one another, as for example both the color-mixing order and categories that represent logic have greatest and least objects. To pinpoint such similarities and understand what they mean, it is useful to have formal ways to connect categories with one another. The simplest type of connection is the good old isomorphism.
In chapter 1 we talked about *set isomorphisms*, which establish an equivalence between two sets. In case you have forgotten, a set isomorphism is a *two-way function* between two sets.
Then, in chapter 4, we encountered *order isomorphisms* and we saw that they are like set isomorphisms, but with one extra condition - aside from just being there, the functions that define the isomorphism have to preserve the order of the object e.g. a greatest object of one order should be connected to the greatest object of the other one, a least object should be connected to a least object and same for all objects in between.
Now we will generalize the definition of order isomorphisms, so it also applies to all other categories (to categories that may have more than one morphism between two objects):
> Given two categories, an isomorphism between them is an invertible function between the underlying sets of objects, *and* an invertible function between the morphisms that connect them, which maps each morphism from one category to a morphism *with the same signature*.
If we examine it closely we will see that, although it *sounds* a bit more complex, this definition is actually the same definition as one we have for orders, it is just that the so-called "morphism functions" between categories that have just one morphism for any two objects, are trivial - we always map the single morphism of the source category to the single morphism of the target category (which is guaranteed to exist, due to the *order-preserving* condition.)
However, when we can have more than one morphism between two given objects we need to make sure that each morphism in one category has a corresponding morphism in the other one.
As you see, categorical isomorphisms are easy to define, however there is another issue with them, namely that they are *very rare in practice* (the only one that comes to mind to me is the Curry-Howard-Lambek isomorphism from the last section) as two categories that are isomorphic are basically the same category.
In the next chapter, we will see in detail why the whole concept of categorical isomorphism is not useful, and we will devise a more apt way to define a *two-way connection* between categories. But first, we will define *one-way connections* between them, i.e. *functors*.
The logician Rudolf Carnap invented the word "functor" as part of his project to formalize the syntax for the natural languages such as English, in order to create a precise way to talk about science. Originally, he took it to mean a phrase whose meaning can be customized by combining it with numerical values, such as the phrase "the temperature at $x$ o'clock" (which has a different meaning depending on the value of $x$).
In other words, a functor is a phrase that acts as a function, only not a function between sets, but one between *linguistic concepts* (such as times and temperature.)
Later, one of the inventors of category theory Sanders Mac Lane borrowed the word, to describe a function between *categories* as well, which he defined in the following way:
> A functor between two categories (let's call them $A$ and $B$) consists of a pair of mappings - a mapping that maps each *object* in $A$ to an object in $B$ and a mapping that maps each *morphism* between any objects in $A$ to a morphism between objects in $B$, in a way that *preserves the structure* of the category.
We said that, a functor contains a mapping between the categories' objects, and we used the word "mapping" to avoid misusing the word "function" which is a term that has a precise meaning since chapter 1. In this particular case, however, it wouldn't be a misuse - the mapping between the categories' objects is just a regular old function.
Or more formally, the object mapping of the functor is a function between the two categories' *underlying sets*, and underlying set of a category being the set of its objects. With the definition of a function being the following:
> A function is a relationship between two sets that matches each element of one set, called the *source set* of the function, with exactly one element from another set, called the *target set* of the function.
The other mapping that forms the functor is not so straightforward - it is a mapping between the categories' morphisms. This mapping resembles a function as well, but with the added requirement that each morphism with a given source and target must be mapped to a morphism with a corresponding source and target, as per the object mapping.
A more formal definition of a morphism mapping involves the concept of the *homomorphism set* - this is a set that contains all morphisms that go between given two objects in a given category.
Utilizing this concept, we can say that a mapping between the morphisms of the two categories is actually a set of the functions between their respective homomorphism sets.
So these are the two mappings that constitute a functor. But not every such pair of mappings is a functon. As we said, in addition to existing, the mappings should *preserve the structure* of the source category into the target category.
2. Functors should also *preserve composition* i.e. for any two morphisms $f$ and $g$, the morphism that corresponds to their composition $F(g•f)$ in the source category should be the same as the morphism that corresponds to the composition of their counterparts in the target directory, so $F(g•f) = F(g)•F(f)$.
And these laws conclude the definition of functors - a simple but, as we will see shortly, very powerful concept. To see *why* is it so powerful, let's check some examples.
We will start with an example of a functor that is very *meta* - the diagrams/illustrations in this book.
You might have noticed that diagrams play a special role in category theory - while in other disciplines they only serve a complementary function i.e. they only show what is already defined in another way, here *the diagrams themselves serve as definitions*.
So in other words we *used the diagram as a definition* of functional composition. This is cool, but kinda confusing at first - definitions in mathematics are supposed to be formal, so if we want to use diagrams as definitions we must first formalize the definition of a diagram itself.
But how do we do that? One key observation is that diagrams look as small finite categories, as, for example, the above definition looks like the category $3$, which we saw earlier (and the fact that the diagram commutes means just that the morphism in the finite category are sometimes composites of one another.)
However, finite categories, by themselves, are only part of the story, as they are just structures, whereas diagrams are *signs* i.e. They are "something by knowing which we know something more.", as Peirce tells us (or "...which can be used in order to tell a lie", in the words of Umberto Eco.)
And so, you can already see that the concept of a functor plays a very important role in category theory. Because of it, diagrams in category theory can be *specified formally* i.e. they are categorical objects *per se*.
You might even say that they are categorical objects *par excellance* (TODO: remove that last joke.)
Functors are sometimes called "maps" for a good reason - maps, like all other diagrams are functors. For example, if we consider a map of different cities and roads between them categorically, then a diagram is a map of the region where the cities are located (or an index category as we dubbed it in the definition), together with a functor connectin it to the region that it represents (i.e. a mapping from the objects in the map to real-world objects.)
The law of preserving composition tells us that the route we create on a map corresponds to a real-world route.
Notice that in order to be a functor, a map does not have to list *all* roads that exist in real life, and *all* travelling options ("the map is not the territory"), the only requirement is that *the roads that it lists should be actual* - this is a characteristic shared by all many-to-one relationships (i.e. functions.)
As you can see from the last two chapters, we, humans, make a good use of functors in our thinking (especially considering that most of us don't know anything about them.) In my [blog post about using logic to model real-life thinking](/logic-thought)) I argue that is because human perception, human thinking is itself functorial.
My thesis is that to perceive the world around us, we are creating a bunch of functors that go from more raw "low-level" maps to more abstract "high-level" ones.
For example, our brain creates a functor between the category of raw sensory data that we receive from our senses, to a category containing some basic model of how the world works (one that tells us where are we in space, how many objects are we seeing etc.) Then we are connecting this model to another, more abstract model, which provides us with a higher-level view of the situation that we are in, and so on.
You can view this progression of more simple to more abstract functors to a progression from categories with less morphisms to categories with more morphisms - we start with the category of pieces of sensory data that have no connections between one another, and proceed to another category where some of these pieces of data are connected. Then, we transfer this structure in another category with even more connnections.
This is, of course, all just a speculation. But how can we check if it is true. You might say that if it were true, functors would be everywhere i.e. all mathematical objects would have functors and functors will play a significant role for them. As we will see in the next chapters, this is not far from the truth.
In group theory, there is this cool thing called *group homomorphism* (or *monoid homomorphism* when we are talking about monoids) - it is a function between the groups' underlying sets which preserves the group operation.
If the time of the day right now is 00:00 o'clock (or 12 PM) then what would the time be after $n$ hours? The answer to this question can be expressed as a function with the set of integers as source and target.
This function is interesting - it preserves the operation of (modular) addition. That is, 13 hours from now the time will be 1 o'clock and if 14 hours from now it will be 2 o'clock, then the time after (13 + 14) hours will be (1 + 2) o'clock.
Or to put it formally, if we call it (the function) $F$, then we have the following equation - $F(a + b) = F(a) + F(b)$ (where $+$ in the right-hand side of the equation means modular addition) Because this equation holds, the $F$ function is a *group homomorphism* between the group of integers under addition and the group of modulo arithmetic with base 11 under modular addition (where you can replace 11 with any other number.)
The groups don't have to be so similar for there to be a homomorphism between them. Take, for example, the function that maps any number $n$ to 2 to the *power of $n$,* so $n \to 2ⁿ$ (here, again, you can replace 2 with any other number.) This function gives a rise to a group homomorphism between the group of integers under addition and the integers under multiplication, or $F(a + b) = F(a) * F(b)$
Wait, what were we talking about, again? Oh yeah - group homomorphisms are functors. To see why, we switch to the category-theoretic representation of groups and revisit our first example and (to make the diagram simpler, we use $mod2$ instead of $mod11$.)
Groups/monoids have just one object when viewed as categories, so there is also only one possible object mapping between any couple of groups/monoids - one that maps the (one and only) object of the source group to the object of the target group (not depicted in the diagram).
Because of the above, the morphism mapping is the only relevant component of the group homomorphism. In the category-theoretic perspective group objects are morphisms and so the morphism mapping is just mapping between the group's objects, as we can see in the diagram.
The first functor law trivial, it just says that the one and only identity object of the source group (which corresponds to the identity morphism of its one and only object) should be mapped to the one and only identity object of the target group. And we can see that this is the case - in our first example, $0$, the identity of the addition operation, is mapped to $0$. And in the second one $0$ is mapped to $1$ - the identity object of the multiplication operation.
$F(a + b) = F(a) \times F(b)$ (where the $+$ and $\times$ operators are arbitrary.) And if you remember that, when interpreted categorically, group objects (like $1$ and $2$ $3$ etc.) correspond to morphisms (like $+1$, $+2$ $+3$ etc.) and the monoid operation of combining two objects corresponds to *functional composition*, you would see that this equation is actually a just a formulation of the second functor law: $F(g•f) = F(g)•F(f)$.
And many algebraic operations satisfy this equation, for example the functor law for the group homomorphism between $n \to 2ⁿ$ is just the famous algebraic rule, stating that $gᵃ gᵇ= gᵃ⁺ᵇ$.
**Task:** Although it's trivial, we didn't prove that the first functor law (the one about the preservation of identities always holds. Interestingly enough, for groups/monoids it actually follows from the second law. Try to prove that. Start with the definition of the identity function.
And now let's talk about one concept that is completely unrelated to functors, nudge-nudge (hey, bad jokes are better than no jokes at all, right?) In the theory of orders, we have the concept of functions between orders (which is unsurprising, given that orders, like monoids/groups, are based on sets.) One very interesting type of such function, which has applications in calculus and analysis, is a *monotonic function* (also called *monotone map*) - this is a function between two orders that *preserves the order of the objects in the source order, in the target order. So a function $F$ is monotonic when for every $a$ and $b$ in the source order, if $a ≤ b$ then $F(a) ≤ F(b)$.
For example, the function that maps the current time to the distance traveled by some object is monotonic because the distance traveled increases (or stays the same) as time increases.
With monoids, the object mapping component of functors was trivial. Here is the reverse - the morphism mapping is trivial - given a morphism between two objects from the source order, we map that morphism to the morphism between their corresponding objects in the target order. The fact that the monotonic function respects the order of the elements, ensures that the latter morphism exists.
And the second law ($F(g•f) = F(g)•F(f)) also follows trivially: both morphisms $F(g•f)$ and $F(g)•F(f)$ have the same type signature - so for example if we take the signature of $f$ and $g$ to be $f :: a \to b$ and $g :: b \to c$, then they both would go from $F(a)$ and $F(c)$. But because in orders there can be just one morphism between $F(a)$ and $F(c)$ so these two morphisms must be equal to one another.
Then, if we compose those two morphisms in the target order ($F(g)•F(f)$), we get a morphism from object $F(a)$ to object $F(c)$ ($F(g)•F(f) :: F(a) \to F(c)$.)
If we compose the two morphisms in the source order, and we use the functor to get the corresponding morphism in the target order ($F(g•f)$) we get another morphism from object $F(a)$ to object $F(c)$ ($F(g•f) :: F(a) \to F(c)$)
But because in orders there can be just one morphism between $F(a)$ and $F(c)$ so these two morphisms must be equal to one another.
In calculus, there is this concept of *linear functions* (also called "degree one polynomials") that are sometimes defined as functions of the form $f(x) = xa$ i.e. ones that contain no operations other than multiplying the argument by some constant (designated as $a$ in the example).
But if we start plotting some such functions we will realize that there is another way to describe them - their graphs are always comprised of straight lines.
Another interesting property of these functions is that most of them *preserve* addition, that is for any $x$ and $y$, you have $f(x) + f(y) = f(x + y)$.
And if you pay attention, you would know that you just saw the functor law formula. So linear functions are just *functors between the group of natural numbers under addition and itself.* (more generally, they are functors in the category of vector spaces.)
And if we view that natural numbers as an order, linear functions are also functors as well, as all functions that are plotted with straight lines are obviously monotonic.
The above definition has one caveat: not all functions that are straight lines preserve addition - functions of the form $f(x) = x * a + b$ in which $b$ is non-zero, are also straight lines (and are also called linear) but they don't preserve addition.
If types in programming language form a category, then what are the functors that are related to that category?
The short (but complex) answer to this question is that we can view functors between the category of types and itself as maps from the realm of simple (primitive) types and functions to the realm of more complex types and functions.
The long but simple answer - giving a definition of functor in programming context, is as simple as changing the terms we use, according to the table in chapter 2, and (more importantly) changing the font we use in our formulas from "modern" to "monospaced"
> A functor between two categories (let's call them `A` and `B`) consists of a mapping that maps each *type* in `A` to a type in `B` and a mapping that maps each *function* between types in `A` to a function between types in `B`, in a way that preserves the structure of the category.
Mathematicians and programmers - two very different communities, that are united by their appreciation of peculiar typefaces. And by the fact that they all use functors.
The first component of a functor is a mapping that converts one type (let's call it `A`) to another type (`B`). So it is *like a function, but between types*. Such constructions are supported by almost all programming languages that have static type checking in the first place - they go by the name of *generic types*.
A generic type is nothing but a function (sometimes called a *type-level function*) that maps one concrete type to another concrete type. For example, the type `Array<A>` maps the type `String` to `Array<String>`, `Number` to `Array<Number>` etc.
So the type mapping of a functor is simply a generic type in a programming language (we can also have functors between two generic types, but we will review those later.) However the nontrivial part of the functor is the *function mapping* - that is a mapping that convert any function operating on simple types, like `String ➞ Number` to a function between their more complex counterparts e.g. `Array<String> ➞ Array<Number>`.
In programming languages, this mapping is represented by a higher-order function called `map` with a signature (using Haskell notation), `(a ➞ b) ➞ (Fa ➞ Fb)`, where `F` represents the composite type.
Any function with that type signature that follows the laws gives rise to a functor, but not all such functors are useful. In practice, usually, there is only one of them that makes sense for a given generic type. For example, in the case of list and similar structures, `map` is a function that applies the original function (the one that converts simple types) to all elements of the list.
Because only one `map` function per generic type is useful (and also for simple convenience) you might sometimes see `map` defined directly in the generic datatype, as a method. For example, Here is how the list functor might look in TypeScript, implemented in the way that I described above:
Aside from facilitating code reuse by bringing in all standard functions of simple types in a more complex context, `map` allows us to work in a way that is predictable, courtesy of the functor laws, which in programming context look like this.
Now, that we have seen some examples of functors, let's attempt to answer the million-dollar question: "How are functors *useful*?" (sometimes formulated also as "Why are you wasting my/your time with this (abstact) nonsense?") We just saw that *maps are functors* and we know that *maps are useful*, so let's start from there.
So why is a map (or any other kind of diagram) useful? Well, it obviously has to do with the fact that the points and arrows of the map corresponds to the cities and the roads in the place you are visiting in i.e. because of the very fact that it is a functor.
But there is a second aspect as well. Maps (or at least those of them that are useful) are *simpler to work with* than the actual things they represent.
For example, road maps are useful, because it is much easier to go through all routes between two given places by following a map, than to actually drive through all these routes in real life.
So why do programmers need functors? Because simple types like `string`, `number`, `boolean` etc are... well simple, there are numerous functions between those types, that are defined in all kinds of libraries e.g. there are a myriad functions that convert a number to boolean.
![Functions from array to boolean](set_arrows.svg)
Functors like `List`, allow you to take all such functions (ones that act on simple types) and derive their counterparts that work on list e.g. a function that converts strings to numbers can be used to convert string arrays to number arrays.
Note that not all functions that act on a list of strings can be derived from mere string functions, but some of them can (some are better than nothing, right?)
Functors
===
Constant functor
---
When we think about diagram functors (and even functors in general), our intuition is to think of every object in the source category being mapped to a *different* object in the target. But that is not always the case. An interesting functor that doesn't follow that rule is the *constant functor* - one that maps *all* objects of the source category to a single object in the target (and all morphisms go to the identity morphism.
![Constant functor](constant_functor.svg)
This one that plays a part in some definitions that we will see later.
In the programming example, we acted like different type families belong to different categories. However, that is not the case - they are actually one and the same category - the category of types (which can be seen as similar to the category of sets.) So all functors used in programming are *endofunctors* i.e. ones in which the source and target category is one and the same. This doesn't make any difference when it comes to the above definitions (you can also think of the different type families as belonging to different categories if that's easier for you), but it does make a difference in other situations, for example, you can apply an endofunctor $F$ to a given value $a$ infinitely many times, adding more and more levels of nesting.
This might look weird, but it does not lead to any type of paradox e.g. there is nothing wrong about a list that contains other lists, and you can have a list of lists of lists, or a list of lists of lists of lists etc, and the functor laws would still hold (provided that you `map` the right number of times.)
There is one particular endofuctor that will probably look familiar to you - it is the *identity functor* of each category, the one that maps each object and morphism to itself.
Identity functors are defined for the same reason as identity morphisms - they allow us to talk about value-related stuff without actually involving values.
An interesting "species" of the endofunctors that we can define using the identity functor are the so-called *pointed* functors. This is a name for the functors that are *isomorphic to the identity functor*.
We still haven't said when two functors are isomorphic, but for now it suffices to say that they are isomorphic when the diagram below commutes for all objects and functions.
If we concentrate on the category of sets (or the category of types, if you will), then this would mean that there is a function that translates each value of what we called the "simple types" to a value of the functor's generic type, in a way that this diagram commutes (again, the function should make the diagram commute for all types (and not just **string** and **num**) for all functions that exist, not only the four we outlined here.)
You can see that the definition of a pointed functor looks like an "upgrade" of the definition of a functor - we again have the relationship between a bunch of objects and a bunch of morphisms, such that there is a symmetry between them. The only difference is that with pointed functors we are working in one and the same category, and so the description of the laws is much simpler - the relationship is
Given any category, we can generate the set of the sets of all morphisms that have a specific type signature with respect to a given object from that category. This is called the *Homomorphism set*, denoted $Hom(B, - )$, $B$ being the object that you picked (for example, let's pick the brown ball.)
This set forms a category where the morphism sets are the objects (again morphism sets are *objects*) and the morphisms are the same as in the original category. And between those two categories (the original and the weird morphism-based one) there is a functor, called the homomorphism functor.
With the homomorphism functors, we can *represent* any category in the category of sets. This is why homomorphism functors and all functors that are isomorphic to them are called *representable* functors.