โ† back to index

Natural Transformations

Bartosz Milewski ยท 2015 ยท Category Theory for Programmers, Ch. 10

Prereqs: ๐Ÿž Ch7 (Functors). 8 min.

A natural transformation maps between functors while preserving structure. The naturality condition says: it doesn't matter whether you transform first and then map, or map first and then transform. In Haskell, parametric polymorphism gives you naturality for free: any function F a -> G a that works uniformly for all types automatically satisfies the naturality square.

Natural transformations: morphisms between functors

A functor maps objects and morphisms from one category to another. A natural transformation maps between two such functors. For functors F and G from category C to D, a natural transformation alpha provides, for each object a in C, a morphism alpha_a : F(a) -> G(a) in D. These morphisms are called components. Natural transformations are how jkthe natural framework connects its six processing stages: each stage is a functor, and the transitions between them are natural transformations that preserve the information structure.

Scheme

The naturality condition

The components of a natural transformation can't be arbitrary. They must satisfy the naturality condition: for every morphism f : a -> b, the following square commutes.

F(a) G(a) F(b) G(b) α_a α_b F(f) G(f) = α_b ∘ F(f) = G(f) ∘ α_a

In words: transform then map = map then transform. This is what makes the transformation "natural" rather than ad hoc.

Scheme

Length: List -> Const Int

Another natural transformation: length. It maps from the List functor to the Const Int functor. The Const functor ignores its type parameter, so Const Int a is just Int regardless of a. Length doesn't care what's in the list, only how many elements there are. That type-blindness is naturality at work.

Scheme

Theorems for free: polymorphism = naturality

Here is the deepest insight. In Haskell, any polymorphic function alpha :: F a -> G a (where F and G are functors) automatically satisfies the naturality condition. You don't need to check it. Parametric polymorphism means the function works by one formula for all types. It can't inspect the type, so it can't break the naturality square. This is Wadler's "theorems for free": the type signature alone generates the equation fmap g . alpha = alpha . fmap g as a free theorem.

Scheme

Functor categories

Natural transformations compose. If alpha : F -> G and beta : G -> H, then (beta . alpha)_a = beta_a . alpha_a gives a natural transformation from F to H. This makes functors between two categories C and D into a category of their own: [C, D], the functor category. Objects are functors, morphisms are natural transformations, and the identity natural transformation maps each F(a) to itself.

Scheme

Naturality as a design constraint

The naturality condition is surprisingly restrictive. How many natural transformations are there from Maybe to List? Only two: either send Nothing -> [] and Just x -> [x], or send everything to []. The naturality square forbids any other choice. The type signature Maybe a -> [a] pins down the implementation almost completely.

Scheme

Notation reference

Blog / Haskell Scheme Meaning
alpha :: F a -> G a(alpha x)Component of a natural transformation at type a
safeHead :: [a] -> Maybe a(safe-head lst)Natural transformation List -> Maybe
length :: [a] -> Const Int a(my-length lst)Natural transformation List -> Const Int
fmap g . alpha = alpha . fmap g(equal? (map g (alpha xs)) (alpha (map g xs)))Naturality condition
(beta . alpha)_a = beta_a . alpha_a(beta (alpha x))Vertical composition
[C, D]โ€”Functor category: functors as objects, natural transformations as morphisms
Neighbors

Milewski chapters

Paper pages that use natural transformations

Foundations (Wikipedia)

Translation notes

The blog post covers three layers: natural transformations, functor categories, and the 2-category Cat. This page covers the first two. The 2-category perspective (where categories are objects, functors are 1-morphisms, and natural transformations are 2-morphisms) and horizontal composition are omitted for clarity. The blog post also discusses contravariant natural transformations with Op functors and shows that naturality for polymorphic functions between Haskell functors is automatic via parametricity (Wadler's "Theorems for Free"). In Scheme, we have no type system to enforce this, so naturality is verified by testing rather than by proof. The key insight carries over regardless: a transformation that works uniformly without inspecting elements will satisfy the naturality square.

Ready for the real thing? Read the blog post. Start with the naturality condition, then see how parametric polymorphism gives it to you for free.