The Yoneda lemma

Read this post with a pencil and paper! Draw pictures!

What is a diagram?

A functor \(\mathcal{C} \to \mathcal{D}\) is basically a way of identifying a copy of \(\mathcal{C}\) inside \(\mathcal{D}\). That is, it’s a specification of an object of \(\mathcal{D}\) for every object of \(\mathcal{C}\), and corresponding morphisms inside \(\mathcal{D}\) which must go between the right objects for this to be a copy of \(\mathcal{C}\).

If we specialise to the category of sets, a functor \(\mathcal{C} \to \mathrm{\mathbf{Set}}\) is a set for every object of \(\mathcal{C}\), and functions between those objects.

Imagine \(\mathcal{C}\) as some kind of abstract template of a universe of types; then a functor \(\mathcal{C} \to \mathrm{\mathbf{Set}}\) is an instantation of that universe of types. For example, perhaps we decide that this particular object of \(\mathcal{C}\) will be instantiated to \(\mathbb{N}\), and that particular object will be instantiated to \(\mathrm{Bool}\), and this arrow between them will be instantiated to \(n \mapsto \mathrm{isEven}(n)\).

Recall what the functor laws in this context are:

  • The functor respects endpoints of morphisms: if \(f: A \to B\) in \(\mathcal{C}\), then \(Ff : FA \to FB\) in \(\mathrm{\mathbf{Set}}\). That is, we really are identifying a copy of \(\mathcal{C}\) in \(\mathrm{\mathbf{Set}}\): we’re not actively breaking the structure in translation. If the template \(\mathcal{C}\) tells us how to get from \(A\) to \(B\), then we can do that in our instantiation.
  • The identity morphism is always taken to the identity function. (This one’s fairly self-explanatory.)
  • The functor respects compositions: \(F(g \circ f) = F(g) \circ F(f)\). That is, if the template tells us we can do \(f\) then \(g\), we can also do that in our instantiation; moreover, if our template tells us two paths are equal, then they’re also equal in the instantiation.

Note what we’re not requiring of our instantiations: that they’re somehow “fully preserving all the structure”. If \(\mathcal{C}\) has two objects \(A\) and \(B\), we’re perfectly happy to instantiate both of them to the same type, as long as all the arrows keep composing correctly. In particular, for example, our instantiation might squash away arbitrarily much of the category’s structure: every category has a trivial instantiation to the universe where there’s only one set \(\emptyset\), and only one arrow \(\mathrm{id} : \emptyset \to \emptyset\).

Homomorphisms between diagrams

Thinking of a diagram as some kind of instantiation of an abstract template, we can define homomorphisms (that is, structure-preserving maps) between them. The concrete example of the “trivial instantiation” in the previous section may help you imagine how these homomorphisms should work.

If we have two diagrams \(F, G : \mathcal{C} \to \mathrm{\mathbf{Set}}\), we can define some particular homomorphism \(\alpha\) from the \(F\)-instantiation to the \(G\)-instantiation by sending every concrete \(F\)-type to a corresponding concrete \(G\)-type. In order to deserve the name “homomorphism”, it had better preserve the structure: that is, if \(x : FA \to FB\) is a function in our concrete instantiation of \(\mathcal{C}\), then it had better be the case that our homomorphism \(\alpha\) takes \(x\) to a suitable corresponding function \(GA \to GB\) in the \(G\)-instantiation.

In fact, every function in the \(F\)-instantiation is an image of a morphism from \(\mathcal{C}\) (that is, we defined our instantiations so that we weren’t considering any extraneous functions there might be between the sets), so instead of considering the set of all general \(x : FA \to FB\), we only need to consider the set of all \(Ff : FA \to FB\). Similarly, the functions \(GA \to GB\) are all of the form \(Gg : GA \to GB\) for some morphism \(g\) of \(\mathcal{C}\).

That is, a homomorphism from diagram \(F\) to diagram \(G\) is:

  • an assignment, for each \(A : |\mathcal{C}|\), of some \(GX\) corresponding to \(FA\) (but note that in fact this \(GX\) must be \(GA\) to meet the later requirements, so there was no choice of target here);
  • an assignment, for each \(\mathcal{C}\)-morphism \(f : A \to B\), of some \(Gg\) corresponding to \(Ff\) (but note that this must be \(Gf\) to meet the later requirements, so similarly there’s no choice of target here);
  • proofs that the homomorphism respects the basic structure of the category: if \(f : A \to B\) in \(\mathcal{C}\), then the map \(Ff : FA \to FB\) gets taken to the map \(Gf : GA \to GB\);
  • proofs that the homomorphism “respects moving around within the diagram”: “moving around in \(F\) and then taking the homomorphism over to \(G\)” should be the same as “taking the homomorphism to \(G\) and then making the same movement in \(G\)”.

The homomorphism \(\alpha\) is pretty constrained: the only freedom is to decide exactly how \(\alpha\) sends \(FA\) to \(GA\) for each \(A : |\mathcal{C}|\).

We have a special name for these structure-preserving maps between diagrams: we call them natural transformations. They provide us with a way of mapping between instantiations of the abstract theory specified by \(\mathcal{C}\).

There are some very special examples of diagrams

We saw already that there are some pretty degenerate diagrams: the one which has every object going to the empty set, for instance. That diagram has somehow “thrown away all the information” from the category.

Diagrams can also be pretty complex. For example, take the diagrams for the very simple category that contains just one object and one arrow. Literally every set in the universe (together with the corresponding identity function on that set) is a diagram for this category! Most of those diagrams involve us ignoring tons of structure.

For example, there are \(\mathbb{R}\)-many functions \(\mathbb{N} \to \mathbb{N}\), so we’re having to ignore uncountably many functions in the category of sets if we take the diagram consisting of “\(\mathbb{N}\) and its sole identity function”. This diagram wants to have way more structure than there was in \(\mathcal{C}\), and it’s only by shutting our eyes and ignoring the set-structure we don’t care about that we recover anything that looks remotely like \(\mathcal{C}\)!

It turns out there’s a sweet spot of diagrams with “exactly the amount of structure \(\mathcal{C}\) specified, and no more”. The construction is: start with only one element in \(FA\) (for some \(A\)), and then chase through everything else that \(\mathcal{C}\) says should exist (which may involve adding in more elements of \(FA\) if there are morphisms telling us there should be more).

What does \(\mathcal{C}\) say should exist? If \(f : A \to B\) is a morphism of \(\mathcal{C}\), and if \(a \in FA\) is an element of our concrete instantiation of the object \(A\), we really want there to be a distinct object \((Ff)(a) \in FB\) so that we’ve preserved the information “\(f\) was a morphism \(A \to B\)”. (If there weren’t any such member of \(FB\), then our diagram has lost information: we might not be able to distinguish any more whether there was a morphism \(f\) in \(\mathcal{C}\) or not, just by looking at our instantiation \(F\).)

So if we assume there’s an element \(a \in FA\), then for every \(B \in |\mathcal{C}|\), we can deduce the existence of elements \((Ff)(a) \in B\) for every \(f : A \to B\) in \(\mathcal{C}\); and they’d better all be distinct if we couldn’t prove them to be equal in \(\mathcal{C}\).

Formally: for each object \(A\) of \(\mathcal{C}\), we can define a diagram \(\mathrm{Rep}_A : \mathcal{C} \to \mathrm{\mathbf{Set}}\) given by sending each \(B\) to the set of all morphisms in \(\mathcal{C}\) which go from \(A\) to \(B\). This somehow “captures exactly all the structure that \(\mathcal{C}\) said \(A\) has”. (I’ve used the symbol \(\mathrm{Rep}\) to denote these diagrams, because the category-theoretic term for a diagram isomorphic to one of these is “representable functor”.)

Note that I haven’t yet written down the functions in these concrete instantiations of \(\mathcal{C}\); there’s only one thing it could plausibly be. Given \(f : B \to C\) a morphism of \(\mathcal{C}\), the corresponding function \(\mathrm{Rep}_A(f) : \mathrm{Rep}_A(B) \to \mathrm{Rep}_A(C)\) (that is, the function \(\mathrm{Rep}_A(f) : \langle \text{morphisms $A \to B$ in $\mathcal{C}$} \rangle \to \langle\text{morphisms $A \to C$ in $\mathcal{C}$}\rangle\)) is defined to be given by composing with \(f\): we send \(g : A \to B\) to \(f \circ g : A \to C\).

These particular diagrams, the representable functors (one for every object in \(\mathcal{C}\)), together tell you everything there is to know about the category. (That is kind of intuitive, by their definition as “the sets of morphisms”: we can list out every morphism in the category, just by writing down every element of every object in each of these concrete instantiations.) What might be less intuitive and requires a bit more thinking is their characterisation as “define \(F\) by supposing there’s some single member \(a \in FA\), and then seeing what else is forced to exist”; you might find it helps to write out a concrete example of performing this operation for some particular tiny categories.

Homomorphisms of the representable functors

The representable functors contain so little structure that their homomorphisms are forced to be quite simple.

Given any diagram \(G : \mathcal{C} \to \mathrm{\mathbf{Set}}\), and given any \(A \in |\mathcal{C}|\), we can precisely characterise the homomorphisms \(\mathrm{Rep}_A \to G\). Remember, \(\mathrm{Rep}_A\) was defined by supposing there’s just one “free generator” element \(a \in \mathrm{Rep}_A(A)\), and then throwing into every object all the other elements that are forced to exist by morphisms of \(\mathcal{C}\). So intuitively speaking it should be the case that a homomorphism \(\mathrm{Rep}_A \to G\) is precisely defined by where that one element \(a\) is sent; once we’ve defined that, everything else in our instantiation \(\mathrm{Rep}_A\) should be forced by the “preserves morphism structure” property of homomorphisms.

This reasoning is made formal in the Yoneda lemma:

Pick an arbitrary diagram \(G : \mathcal{C} \to \mathrm{\mathbf{Set}}\). Then for every object \(A : |\mathcal{C}|\), the homomorphisms from the diagram \(\mathrm{Rep}_A\) to \(G\) are precisely in correspondence with the elements of \(G(A)\). Moreover, this correspondence is natural in both \(A\) and \(G\).

Intuition: the homomorphisms are precisely defined by what happens to the “free generator”, and we can get such a homomorphism from any choice of where the “free generator” goes. Moreover,

  • this construction is respected by homomorphisms out of \(G\) (that’s “naturality in \(G\)”: if we have a homomorphism \(h : G \to H\), and we perform the construction on both \(G\) and \(H\), we find that every homomorphism \(\mathrm{Rep}_A \xrightarrow{\text{Yoneda corresponding to $x \in GA$}} G \xrightarrow{h} H\) is equal to \(\mathrm{Rep}_A \xrightarrow{\text{Yoneda corresponding to $h(x) \in HA$}} H\));
  • this construction is respected by morphisms \(A \to B\) (that’s “naturality in \(A\)”): this is currently entirely an exercise because I’ve ground to a halt.

The precise construction is like so:

  • Given an element \(a \in G(A)\), define a homomorphism \(\mathrm{Rep}_A\) to \(G\) by sending \(f : A \to B\) to \((Gf)(a)\).
  • Given a homomorphism \(\alpha : \mathrm{Rep}_A\) to \(G\), define an element of \(G(A)\) by \(\alpha(\mathrm{id}_A : A \to A)\).
  • Show that these are inverse to each other.
  • Prove the naturality conditions.

Exercise: do those formally, as follows!

  1. Prove that the homomorphism \((f : A \to B) \mapsto (Gf)(a)\) is indeed a homomorphism (that is, a natural transformation), by writing out the necessary properties which define a natural transformation and showing that they each hold.
  2. Prove (by writing out the equations) that the two Yoneda maps are inverse to each other.
  3. Write out the equations for both naturality conditions (that is, in \(A\) and in \(G\)) in full, and prove them.

The Yoneda embedding

Given any (locally-small) category \(\mathcal{C}\) and an object \(A : |\mathcal{C}|\), we’ve seen a way to construct an instantiation of \(\mathcal{C}\) in \(\mathrm{\mathbf{Set}}\) in a canonical way, representing exactly the structure of \(\mathcal{C}\) that was available at \(A\).

Definition of “fully faithful”

Recall the definitions of “full” and “faithful” for a functor \(F : \mathcal{C} \to \mathcal{D}\):

  • The functor is faithful if it is injective on parallel arrows: for all \(A, B : |\mathcal{C}|\), no two morphisms \(A \to B\) get mapped to the same target arrow.
  • The functor is full if it is surjective on objects which came from the functor: for all \(A, B : |\mathcal{C}|\), and for all \(g : FA \to FB\), there is \(f : A \to B\) with \(Ff = g\).

A functor \(\mathcal{C} \to \mathcal{D}\) is fully faithful if it is both full and faithful. While it may collapse away some of \(\mathcal{C}\)’s structure, and while it might not hit all of \(\mathcal{D}\), it does “locally” preserve all of \(\mathcal{C}\)’s structure and introduces no new structure locally: if we fix two objects \(A, B\) in \(\mathcal{C}\) and restrict ourselves to only looking at \(A, B\) and \(FA, FB\), the restricted \(F\) is a bijection.

The Yoneda embedding is fully faithful

Notice that the collection of representable functors (that is, the “sweet spot” instantiations of \(\mathcal{C}\)) has got the right number of objects to try and be a copy of \(\mathcal{C}\): there’s a representable functor for each object of \(\mathcal{C}\) already (because that’s how we defined the representable functors). So what happens if we try and complete this into a copy of \(\mathcal{C}\) with all its categorical structure, inside the much larger space of instantiations of \(\mathcal{C}\)? This would be a nice thing to have, because the space of instantiations of \(\mathcal{C}\) is very well-behaved (they’re all just sets!).

So to view it as a copy of \(\mathcal{C}\), we need for any \(A, B : |\mathcal{C}|\) and any morphism \(f : A \to B\) to find a homomorphism from \(\mathrm{Rep}_A\) to \(\mathrm{Rep}_B\). Take the Yoneda lemma and specialise it by setting \(G := \mathrm{Rep}_B\); then we have that the homomorphisms \(\mathrm{Rep}_A \to \mathrm{Rep}_B\) are naturally in bijection with the elements of \(\mathrm{Rep}_B(A)\), which is by definition \(\mathrm{Hom}_{\mathcal{C}}(B, A)\).

That’s… not actually what we wanted! It’s very close, but the arrows are going the wrong way: we have homomorphisms \(\mathrm{Rep}_A \to \mathrm{Rep}_B\) corresponding naturally to \(\mathrm{Hom}_{\mathcal{C}}(B, A)\).

What we’ve actually done is built a canonical copy of the opposite category of \(\mathcal{C}\) inside the space of instantiations of \(\mathcal{C}\). This canonical copy is called the Yoneda embedding, and you can prove that it is full and faithful.

That was the contravariant Yoneda embedding, which takes \(\mathcal{C}^{\mathrm{op}}\) and embeds it fully faithfully in \(\mathrm{Nat}(\mathcal{C} \to \mathrm{\mathbf{Set}})\), the space of all \(\mathrm{\mathbf{Set}}\)-instantiations of \(\mathcal{C}\). (That space is more precisely a category, with morphisms being precisely the instantiation homomorphisms, or natural transformations.) By flipping all the arrows around, we also get the covariant Yoneda embedding, which takes \(\mathcal{C}\) and embeds it fully faithfully in \(\mathrm{Nat}(\mathcal{C}^{\mathrm{op}} \to \mathrm{\mathbf{Set}})\), the space of all \(\mathrm{\mathbf{Set}}\)-instantiations of \(\mathcal{C}^{\mathrm{op}}\) (also known as the space of all presheaves over \(\mathcal{C}\)).