Category Theory in 20 Minutes: The Map That Makes the Rest Obvious (Part 7 of the Functional Programming Series)
Part 7 of the Functional Programming in Practice series. This is the hinge of the whole series. Everything before it was concrete tools. This part is the one simple idea those tools secretly stand on, and the map for everything still to come.
Hey there, Coding Chefs! 👨💻
Functor. Monoid. Monad. Applicative. These words sound like a secret club with a velvet rope, and the gatekeeping is a big reason people bounce off functional programming. I am going to hand you the one diagram that makes every one of those words stop being scary. It is genuinely simple, almost insultingly so, and once you have it, the rest of this series reads like named patterns instead of arcane spells.
This part is more abstract than the others, and shorter on code on purpose. Bear with me for twenty minutes of dots and arrows. The reward is that concepts which take other courses chapters to land become obvious and intuitive, because you will see the single structure underneath them all. Let's get cracking.
A Category Is Dots and Arrows
Functional programming is built on a branch of mathematics called category theory. Category theory is a kind of parent to many areas of math, set theory and type theory among them, which is part of why it is so powerful: insights proven at this level apply everywhere below it.
So what is a category? A category is a bunch of objects (draw them as dots) and arrows between them (called morphisms). That is the whole raw material. Dots and arrows.
The objects are primitive. They have no internal structure that we care about, they are just points. The arrows start at one object and end at another. Between two objects you can have one arrow or many. You can have arrows going back the other way. You can even have an arrow from an object to itself. So far this is just a doodle.
What turns a doodle into a category is that the arrows must obey three rules, and all three are about composing arrows, that is, chaining them.
The Three Rules
Rule 1: Composition exists
If you have an arrow from A to B, and another arrow from B to C (the second picks up where the first leaves off), then there must also be an arrow from A straight to C. Chaining two arrows that meet always gives you a combined arrow. If f goes A to B and g goes B to C, then their composition (written g ∘ f, "g after f") goes A to C, and it must exist in the category.
If that feels familiar, it should. This is function composition from earlier, stated as a law. A pipe from A to B welded to a pipe from B to C gives a pipe from A to C.
Rule 2: Composition is associative
If you have three arrows chained, A to B to C to D, it does not matter how you group the composing. You can combine the first two and then add the third, or combine the last two and then prepend the first. Both routes produce the exact same final arrow from A to D.
This is the same associativity you know from arithmetic, where (1 + 2) + 3 equals 1 + (2 + 3). The grouping does not change the answer. The benefit is freedom: you never have to remember a "correct order" to compose in, because there is not one. That is what lets you refactor a pipeline by regrouping its steps without fear, and, as a later part will show, it is what makes work safely splittable across machines.
Rule 3: Identity exists
Every object must have an arrow to itself that does nothing, called the identity arrow. "Does nothing" has a precise meaning: composing the identity arrow with any other arrow, on either side, gives back that same arrow unchanged. It is the neutral element of composition, the way 0 is neutral for addition and 1 is neutral for multiplication.
That is the entire definition. Dots, arrows, and three rules about composing arrows: composition exists, it is associative, and there is a do-nothing identity. If your dots and arrows satisfy those three, you have a category. Pretty simple, right?
Why Such a Simple Thing Matters
The natural objection: how does something this minimal lead to real software? The answer is leverage. Category theory is the study of structure and composition in the abstract. Anything that has the shape of "things, ways to connect them, and lawful composition" is a category, and anything mathematicians proved about categories in general is instantly true for your specific case. You inherit a mountain of results for free, just by recognizing that your problem fits the pattern.
There is also a deeper reason it resonates. A category is essentially the formal definition of a structure or a pattern. Humans are pattern-recognition machines, it is how we survived, spotting the predator's eyes in the dark. Category theory is that instinct made rigorous: a way to recognize a pattern, and even to recognize a pattern inside another pattern. Hold that thought, because it is exactly what a Functor turns out to be in the next part.
Let me show you three quick examples so "category" stops being abstract.
Three Categories You Already Understand
Order. Let the objects be things that can be compared, and draw an arrow from one to another when the first is less than or equal to the second. Does composition hold? If A ≤ B and B ≤ C, then A ≤ C, so the composed arrow exists. Associative? Yes, the chain of "less than or equal" does not care about grouping. Identity? Every value is less than or equal to itself, so each object has its do-nothing arrow. All three rules hold. Order is a category.
Subsets. Let the objects be sets, and draw an arrow from one set to another when the first is a subset of the second. If X is a subset of Y and Y is a subset of Z, then X is a subset of Z, composition holds. The chain is associative. And every set is a subset of itself, so identity holds. Subsets form a category.
Types and functions. Here is the one that matters for us. Let the objects be types (the sets-of-values from the foundation), and let the arrows be functions between them. A function from number to string is an arrow from the number object to the string object. Does composition hold? Yes, that is exactly the composition we built: weld a number → string and a string → boolean into a number → boolean. Is it associative? Yes, as long as the functions are pure, grouping the composition any way gives the same result. Is there an identity? Yes, the function (x) => x that returns its input unchanged, one per type, composing with anything to give that thing back.
const identity = <A>(a: A): A => a; // the do-nothing arrow, for every type
All three rules hold. Types and functions form a category. This is the punchline of the whole part.
What This Buys You
That last example is why every word still to come will make sense. The world functional programmers live in is the category of types and functions. Types are the objects, pure functions are the arrows, composition is welding pipes, and identity is the do-nothing function.
So when we say a Functor is "a structure-preserving map between categories," you will not flinch, because you will know a category is just dots, arrows, and lawful composition, and you already have one made of your own types. When we say a Monoid is about an associative operation with an identity element, you will recognize Rules 2 and 3 wearing a different hat. The jargon ahead is not a new vocabulary to memorize. It is a handful of named patterns in this one structure you now understand.
That is the leverage. Learn the abstract shape once, and every specific tool slots into place. The diagram you just internalized, dots and arrows that compose, is the map for the entire back half of this series.
The Honest Conclusion
A category is three things: objects, arrows between them, and three rules about composing those arrows. Composition exists, it is associative, and there is a do-nothing identity. That is the whole foundation functional programming stands on, and you can hold all of it in your head at once.
The reason we bothered with the abstraction is leverage. Recognize that your types and functions form a category, and every result about categories becomes a free tool. More practically, this map is what turns Functor, Monoid, and Monad from intimidating math words into obvious named patterns, which is exactly what the next several parts will show.
If you want to go deeper than this twenty-minute tour, Bartosz Milewski's category theory lectures are the gold standard, and worth every hour. But you do not need them to ship. You need the diagram.
You do not need the math to write functional code. But once you see that types and functions are just dots and arrows that compose, every tool in this series stops being magic and starts being obvious.
Next up: We cash in the map immediately. Next we meet Magma, Semigroup, and Monoid, the algebra of combining things, and you will discover that half the reduce calls you have ever written are secretly the same function wearing different clothes.