
The Math of Composition
Category theory is often called the “mathematics of mathematics.” But for us as developers, it should be thought of as the mathematics of composition.
At its heart, programming is just the act of taking small components and sticking them together to make larger ones. We compose functions, we compose objects, and we compose entire services. Category theory provides the formal proof that these compositions are valid and predictable.
1. What is a Category? (The Three Laws)
To call a collection of things a Category, it must follow three simple rules:
- Objects: Think of these as your Types (e.g.,
Int,String,User). - Morphisms (Arrows): These are your Functions ($f: A \to B$). They connect one object to another.
- Composition: If you have a function $f$ from $A$ to $B$, and a function $g$ from $B$ to $C$, you must be able to create a third function $h$ that goes directly from $A$ to $C$. This is written as $g \circ f$.
The Laws of the Land:
- Identity: Every object $A$ must have an identity arrow ($id_A$) that does nothing.
- Associativity: When composing three functions ($h \circ g \circ f$), the order in which you group them doesn’t matter.
2. Why Programmers Love (and Fear) It
Concepts that feel like “magic” in languages like Haskell, Scala, or even TypeScript have their rigid roots in this math.
- Functors (Map): A Functor is a way to take a category of “Normal Values” and map them into a category of “Wrapped Values” (like an
Arrayor anOption). - Monads (FlatMap): This is the one that causes the most confusion. A Monad is simply an “Endofunctor” with some extra structure that allows you to chain operations that return wrapped values without getting double-wrapped results (like
List<List<Int>>). - Monoids: A type where you have a “Zero” value and a way to combine two values (like
0and+for integers, or""and+for strings).
3. Comparative Taxonomy of Abstractions
| Concept | Programming Interpretation | Category Theory Term |
|---|---|---|
| Type | A set of possible values. | Object |
| Function | A transformation of data. | Morphism |
| Generics | A way to parameterize types. | Natural Transformation |
| Map | Applying a function inside a container. | Functorial Mapping |
| The Null Object | A default, neutral value. | Identity / Unit |
4. Code Corner: Functors in TypeScript
You don’t need Haskell to see category theory in action. Every time you use .map(), you are using a Functor.
// A Functor must preserve composition and identity.
const double = (x: number) => x * 2;
const addFive = (x: number) => x + 5;
const numbers = [1, 2, 3];
// Composed mapping is the same as mapping the composition
const resultA = numbers.map(x => addFive(double(x)));
const resultB = numbers.map(double).map(addFive);
console.log(resultA); // [7, 9, 11]
console.log(resultB); // [7, 9, 11] (Law of Composition preserved!)
Conclusion: Becoming a Better Architect
Learning category theory doesn’t make you a faster “coder”—it makes you a more profound “architect.” It gives you a language to describe why certain abstractions work while others feel “clunky.” It allows you to see the deep, underlying symmetries that connect a data transformation pipeline at Google to the internal logic of a 1960s mathematics proof.
If you can master the math of composition, you can build systems that are not just working, but provably elegant.
References & Further Reading
- Bartosz Milewski: Category Theory for Programmers (The industry standard guide)
- Saunders Mac Lane: Categories for the Working Mathematician
- Computerphile: Monads - What are they and why are they everywhere?
- TypeLevel: Category Theory for Scala Developers