The Yoneda Lemma
Bartosz Milewski ยท 2015 ยท Category Theory for Programmers, Ch. 14
Prereqs: ๐ Ch10 (Natural Transformations), ๐ Ch13 (Representable Functors). 10 min.
Nat(Hom(a, –), F) ≅ F(a). Natural transformations from a hom-functor to any functor F are in bijection with elements of F(a). An object is completely determined by its relationships to every other object. The entire natural transformation crystallizes from a single value: what you assign to the identity morphism.
The hom-functor: an object seen from the outside
Fix an object a in a category. The hom-functor Hom(a, –) maps every object x to the set of morphisms from a to x. In Haskell, this is the Reader a functor: Reader a x = a -> x. It captures everything a can "see" in the category.
The Yoneda bijection: one value determines everything
A natural transformation α from Hom(a, –) to a functor F is a polymorphic function: for every x, it takes an (a → x) and returns an F x. The Yoneda lemma says: every such natural transformation is determined by a single element of
F(a). To recover it, apply α to the identity morphism. To go the other way, take an element of F(a) and fmap any function over it.
Why it works: naturality forces your hand
The naturality condition for α says: α_y ˆ Hom(a, f) = F(f) ˆ α_x. Apply this at x = a with the identity morphism id_a. The left side gives α_y(f). The right side gives F(f)(α_a(id_a)). So once you choose α_a(id_a), the value at every other component is forced: α_y(f) = fmap f (α_a(id_a)). One seed, the whole flower.
Length: a natural transformation in the wild
length is a natural transformation from List to Const Int. It turns a [a] into an Int regardless of the element type. Yoneda says this nat. trans. corresponds to a single element of Const Int (a) when the domain is a hom-functor, but here we see the pattern: length is natural because it doesn't inspect the elements. It commutes with fmap: length (map f xs) = length xs.
Yoneda embedding: objects as their morphisms
Set F = Hom(b, –) in the Yoneda lemma. Then Nat(Hom(a, –), Hom(b, –)) ≅ Hom(b, a). Every natural transformation between hom-functors comes from a morphism. This means the mapping a ↦ Hom(a, –) is a full and faithful embedding: it preserves all morphisms, losing nothing. An object is completely characterized by its web of relationships.
Co-Yoneda: the contravariant dual
The co-Yoneda lemma applies the same trick to the contravariant hom-functor Hom(–, a). Now: Nat(Hom(–, a), F) ≅ F(a) for contravariant functors F. In Haskell: (forall x . (x → a) → F x) ≅ F a. The identity trick works the same way, but the arrows point backwards.
Continuation-passing style: Yoneda with F = Identity
Set F = Identity in the Yoneda lemma. Then (forall x . (a → x) → x) ≅ a. A value of type a is the same thing as a function that takes any continuation a → x and produces an x. This is continuation-passing style. The Yoneda lemma is the theoretical justification for CPS transforms.
Notation reference
| Blog / Haskell | Scheme | Meaning |
|---|---|---|
| C(a, x) / Reader a x | (lambda (x) ...) | Hom-set / hom-functor |
| Nat(C(a,-), F) ≅ F a | (phi alpha) = (alpha id) | Yoneda lemma |
| phi alpha = alpha id | (alpha (lambda (x) x)) | Extract element at identity |
| psi x h = fmap h x | (map h fa) | Rebuild nat. trans. from element |
| forall x . (a -> x) -> x | (to-cps val) | CPS / Yoneda at Identity |
| a ↦ C(a, -) | (alpha h) = (h . g) | Yoneda embedding |
Neighbors
Milewski chapters
- ๐ Chapter 10 โ Natural Transformations: the morphisms between functors
- ๐ Chapter 13 โ Representable Functors: functors isomorphic to hom-sets
Paper pages that use these concepts
- ๐ Capucci 2021 โ optics use the Yoneda lemma to show profunctor and concrete representations coincide
- ๐ Leinster 2021 โ entropy as a functor, representability connects to Yoneda
Foundations (Wikipedia)
Translation notes
The blog post proves Yoneda for locally small categories with Set-valued functors. This page stays in the programming world: functors are type constructors with fmap, natural transformations are polymorphic functions, and the bijection is demonstrated by round-tripping through phi and psi. The key subtlety the blog post emphasizes: in Haskell, polymorphic functions are automatically natural (parametric polymorphism guarantees naturality via the "theorem for free"). In category theory, naturality is an additional condition that must be checked. The co-Yoneda section on this page uses predicates for concreteness. Milewski states it more generally for presheaves (contravariant functors to Set). The Yoneda embedding (full and faithful) is the deeper payoff: it means every category embeds into a functor category, so abstract morphisms can always be studied as concrete functions between sets.