In the previous blog post we talked about relations. I gave an example of a thin category as a kind of relation that’s compatible with categorical structure. In a thin category, the hom-set is either an empty set or a singleton set. It so happens that these two sets form a sub-category of Set. It’s a very interesting category. It consists of the two objects — let’s give them new names
i. Besides the mandatory identity morphisms, we also have a single morphism going from
i, corresponding to the function we call
absurd in Haskell:
absurd :: Void -> a absurd _ = a
This tiny category is sometimes called the interval category. I’ll call it o->i.
The object o is initial, and the object i is terminal — just as the empty set and the singleton set were in Set. Moreover, the cartesian product from Set can be used to define a tensor product in o->i. We’ll use this tensor product to build a monoidal category.
A tensor product is a bifunctor ⊗ with some additional properties. Here, in the interval category, we’ll define it through the following multiplication table:
o ⊗ o = o o ⊗ i = o i ⊗ o = o i ⊗ i = i
Its action on pairs of morphisms (what we call
bimap in Haskell) is also easy to define. For instance, what’s the action of
⊗ on the pair
<absurd, idi>? This pair takes the pair
<o, i> to
<i, i>. Under the bifunctor
⊗, the first pair produces
o, and the second
i. There is only one morphism from
i, so we have:
absurd ⊗ idi = absurd
If we designate the (terminal) object
i as the unit of the tensor product, we get a (symmetric) monoidal category. A monoidal category is a category with a tensor product that’s associative and unital (usually, up to isomorphism — but here, strictly).
Now imagine that we replace hom-sets in our original thin category with objects from the monoidal category o->i (we’ll call them hom-objects). After all, we were only using two sets from Set. We can replace the empty hom-set with the object
o, and the singleton hom-set with the object
i. We get what’s called an enriched category (although, in this case, it’s more of an impoverished category).
An enriched category has hom-objects instead of hom-sets. These are objects from some monoidal category V called the base category. The base category has to be monoidal because we want to define something that would replace the usual composition of morphisms. Morphisms are elements of hom-sets. However, hom-objects, in general, have no elements. We don’t know what an element of o or i is.
So to fully define an enriched category we have to come up with a sensible substitute for composition. To do that, we need to rethink composition — first in terms of hom-sets, then in terms of hom-objects.
We can think of composition as a function from a cartesian product of two hom-sets to a third hom-set:
composea b c :: C(b, c) × C(a, b) -> C(a, c)
Generalizing it, we can replace hom-sets with hom-objects (here, either o or i), the cartesian product with the tensor product, and a function with a morphism (notice: it’s a morphism in our monoidal category o->i). These composition-defining morphisms form a “composition table” for hom-objects.
As an example, take the composition of two
is. Their product
i ⊗ i is
i again, and there is only one morphism out of
i, the identity morphism. In terms of original hom-sets it would mean that the composition of two morphisms always exists. In general, we have to impose this condition when we’re defining a category, enriched or not — here it just happens automatically.
For instance (see illustration),
compose0 1 2=idi:
compose0 1 2 (C(1, 2) ⊗ C(0, 1)) = compose0 1 2 (i ⊗ i) = compose0 1 2 i = i = C(0, 2)
In every category we must also have identity morphisms. These are special elements in the hom-sets of the form
C(a, a). We have to find a way to define their equivalent in the enriched setting. We’ll use the standard trick of defining generalized elements. It’s based on the observation that selecting an element from a set
s is the same as selecting a morphism that goes from the singleton set (the terminal object in Set) to
s. In a monoidal category, we replace the terminal object with the monoidal unit.
So, instead of picking an identity morphism in
C(a, a), we use a morphism from the monoidal unit
ja :: i -> C(a, a)
Again, in the case of a thin category, there is only one morphism leaving
i, and that’s the identity morphism. That’s why we are automatically guaranteed that, in a thin category, all hom-objects of the form
C(a, a) are equal to
Composition in a category must also satisfy associativity and identity conditions. Associativity in the enriched setting translates straightforwardly to a commuting diagram, but identity is a little trickier. We have to use
ja to “select” the identity from the hom-object
C(a, a) while composing it with some other hom-object
C(b, a). We start with the product:
i ⊗ C(b, a)
i is the monoidal unit, this is equal to
C(b, a). On the other hand, we can tensor together two morphisms in
o->i — remember, a tensor product is a bifunctor, so it also acts on morphisms. Here we’ll tensor
ja and the identity at
ja ⊗ idC(b, a)
We act with this product on the product object
i ⊗ C(b, a) to get
C(a, a) ⊗ C(b, a). Then we use composition to get:
C(a, a) ⊗ C(b, a) -> C(b, a)
These two ways of getting to
C(b, a) must coincide, leading to the identity condition for enriched categories.
Now that we’ve seen how the enrichment works for thin categories, we can apply the same mechanism to define categories enriched over any monoidal category V.
The important part is that V defines a (bifunctor) tensor product ⊗ and a unit object
i. Associativity and unitality may be either strict or up to isomorphism (notice that a regular cartesian product is associative only up to isomorphism —
(a, (b, c)) is not equal to
((a, b), c)).
Instead of sets of morphisms, an enriched category has hom-objects that are objects in V. We use the same notation as for hom-sets:
C(a, b) is the hom-object that connects object
a to object
b. Composition is replaced by morphisms in V:
composea b c :: C(b, c) ⊗ C(a, b) -> C(a, c)
Instead of identity morphisms, we have the morphisms in V:
ja :: i -> C(a, a)
Finally, associativity and unitality of composition are imposed in the form of a few commuting diagrams.
The Yoneda Lemma talks about functors from an arbitrary category to Set. To generalize the Yoneda lemma to enriched categories we first have to generalize functors. Their action on objects is not a problem; it’s the action on morphisms that needs our attention.
Since in an enriched category we no longer have access to individual morphisms, we have to define the action of functors on hom-objects wholesale. This is only possible if the hom-objects in the target category come from the same base category V as the hom-objects in the source category. In other words, both categories must be enriched over the same monoidal category. We can then use regular morphisms in V to map hom-objects.
Between any two objects
b in C we have the hom-object
C(a, b). The two objects are mapped by the functor
f a and
f b, and there is a hom-object between them,
D(f a, f b). The action of
C(a, b) is defined as a morphism in V:
C(a, b) -> D(f a, f b)
Let’s see what this means in our impoverished thin category. First of all, a functor will always map related objects to related objects. That’s because there is no morphism from
o. A bond between two objects cannot be broken by an impoverished functor.
If the relation is a partial order, for instance less-than-or-equal, then it follows that a functor between posets preserves the ordering — it’s monotone.
A functor must also preserve composition and identity. The former can be easily expressed as a commuting diagram. Identity preservation in the enriched setting involves the use of
ja. Starting from
i we can use
ja to get to
C(a, a), which the functor maps to
D(f a, f a). Or we can use
jf a to get there directly. We insist that both paths be the same.
In our impoverished category, this just works because
ja is the identity morphism and all
C(a, a)s and
D(a, a)s are equal to
Back to Yoneda: You might remember that we start the Yoneda construction by fixing one object
a in C, and then varying another object
x to define the functor:
x -> C(a, x)
This functor maps C to Set, because
xs are objects in C, and hom-sets are sets — objects of Set.
In the enriched environment, the same construction results in a mapping from C to V, because hom-objects are objects of the base category V.
But is this mapping a functor? This is far from obvious, considering that C is an enriched category, and we have just said that enriched functors can only go between categories that are enriched over the same base category. The target of our functor, the category V, is not enriched. It turns out that, as long as V is closed, we can turn it into an enriched category.
Let’s first see how we would enrich our tiny category o->i. First of all, let’s check if it’s closed. Closedness means that hom-sets can be objectified — for every hom-set there is an object called the exponential object that objectifies it. The exponential object in a (symmetric) monoidal category is defined through the adjunction:
V(a⊗b, c) ≅ V(b, ca)
This is the standard adjunction for defining exponentials, except that we are using the tensor product instead of the regular product. The hom-sets are sets of morphisms between objects in V (here, in o->i).
Let’s check, for instance, if there’s an object that corresponds to the hom-set
V(o, i), which we would call
io. We have:
V(o⊗b, i) ≅ V(b, io)
b we chose, when multiplied by
o it will yield
o, so the left hand side is
V(o, i), a singleton set. Therefore
V(b, io) must be a singleton set too, for any choice of
b. In particular, if
i, we see that the only choice for
io = i
You can check that all exponentiation rules in o->i can be obtained from simple algebra by replacing
o with zero and
i with one.
Every closed symmetric monoidal category can be enriched in itself by replacing hom-sets with the corresponding exponentials. For instance, in our case, we end up replacing all empty hom-sets in the category o->i with
o, and all singleton hom-sets with
i. You can easily convince yourself that it works, and the result is the category o->i enriched in itself.
We can now take a category C that’s enriched over a closed symmetric monoidal category V, and show that the mapping:
x -> C(a, x)
is indeed an enriched functor. It maps objects of C to objects of V and hom-objects of C to hom-objects (exponentials) of V.
Let’s see what this functor looks like in a poset. Given some
a, the hom-object
C(a, x) is equal to
a <= x. So an
x is mapped to
i if it’s greater-or-equal to
a, otherwise it’s mapped to
o. If you think of the objects mapped to
o as colored black and the ones mapped to
i as colored red, you’ll see the object
a and the whole graph below it must be painted red.
Enriched Natural Transformations
Now that we know what enriched functors are, we have to define natural transformations between them. This is a bit tricky, since a regular natural transformation is defined as a family of morphisms. But again, instead of picking individual morphisms from hom-sets we can work with the closest equivalent: generalized elements — morphisms going from the unit object
i to hom-objects. So an enriched natural transformation between two enriched functors
g is defined as a family of morphisms in V:
αa :: i -> V(f a, g a)
Natural transformations are very limited in our impoverished category. Let’s see what morphisms from
i are at our disposal. We have one morphism from
i: the identity morphism
ida. This makes sense — we think of
i as having a single element. There is no morphism from
i back to
o; and that makes sense too — we think of
o as having no elements. The only possible generalized components of an impoverished natural transformation between two functors
g correspond to
D(f a, g a) equal to
i; which means that, for every
f a must be less-than-or-equal to
g a. A natural transformation can only push a functor uphill.
When the target category is
o->i, as in the impoverished Yoneda lemma, a natural transformation may never connect red to black. So once the first functor switches to red, the other must follow.
There is, of course, a naturality condition that goes with this definition of a natural transformation. The essence of it is that it shouldn’t matter if we first apply a functor and then the natural transformation
α, or the other way around. In the enriched context, there are two ways of getting from
C(a, b) to
D(f a, g b). One is to multiply
C(a, b) by
i on the right:
C(a, b) ⊗ i
apply the product of
g ⊗ αa to get:
D(g a, g b) ⊗ D(f a, g a)
and then apply composition to get:
D(f a, g b)
The other way is to multiply
C(a, b) by
i on the left:
i ⊗ C(a, b)
αb ⊗ f to get:
D(f b, g b) ⊗ D(f a, f b)
and compose the two to get:
D(f a, g b)
The naturality condition requires that this diagram commute.
The enriched version of the Yoneda lemma talks about enriched natural transformations from the functor
x -> C(a, x) to any enriched functor
f that goes from C to V.
Consider for a moment a functor from a poset to our tiny category o->i (which, by the way, is also a poset). It will map some objects to
o (black) and others to
i (red). As we’ve seen, a functor must preserve the less-than-or-equal relation, so once we get into the red territory, there is no going back to black. And a natural transformation may only repaint black to red, not the other way around.
Now we would like to say that natural transformations from
x -> C(a, x) to
f are in one-to-one correspondence with the elements of
f a, except that
f a is not a set, so it doesn’t have elements. It’s an object in V. So instead of talking about elements of
f a, we’ll talk about generalized elements — morphisms from the unit object
f a. And that’s how the enriched Yoneda lemma is formulated — as a natural bijection between the set of natural transformations and a set of morphisms from the unit object to
Nat(C(a, -), f) ≅ i -> f a
In our running example, there are only two possible values for
- If the value is
othen there is no morphism from
ito it. The Yoneda lemma tells us that there is no natural transformation in that case. That makes sense, because the value of the functor
x -> C(a, x)at
i, and there is no morphism from
- If the value is
ithen there is exactly one morphism from
ito it — the identity. The Yoneda lemma tells use that there is just one natural transformation in that case. It’s the natural transformation whose generalized component at any object
Strong Enriched Yoneda
There is something unsatisfactory in the fact that the enriched Yoneda lemma ends up using a mapping between sets. First we try to get away from sets as far as possible, then we go back to sets of morphisms. It feels like cheating. Not to worry! There is a stronger version of the Yoneda lemma that deals with this problem. What we need is to replace the set of natural transformations with an object in V that would represent them — just like we replaced the set of morphisms with the exponential object. Such an object is defined as an end:
∫x V(f x, g x)
The strong version of the Yoneda lemma establishes the natural isomorphism:
∫x V(C(a, x), f x) ≅ f a
We’ve seen that a profunctor is a functor from a product category Cop × D to Set. The enriched version of a profunctor requires the notion of a product of enriched categories. We would like the product of enriched categories to also be an enriched category. In fact, we would like it to be enriched over the same base category V as the component categories.
We’ll define objects in such a category as pairs of objects from the component categories, but the hom-objects will be defined as tensor products of the component hom-objects. In the enriched product category, the hom-object between two pairs,
<c, d> and
<c', d'> is:
(Cop ⊗ D)(<c, d>, <c', d'>) = C(c, c') ⊗ D(d, d')
You can convince yourself that composition of such hom-objects requires the tensor product to be symmetric (at least up to isomorphism). That’s because you have to be able to rearrange the hom-objects in a tensor product of tensor products.
An enriched profunctor is defined as an enriched functor from the tensor product of two categories to the (self-enriched) base category:
Cop ⊗ D -> V
Just like regular profunctors, enriched profunctors can be composed using the coend formula. The only difference is that the cartesian product is replaced by the tensor product in V. They form a bicategory called V-Prof.
Enriched profunctors are the basis of the definition of Tambara modules, which are relevant in the application to Haskell lenses.
One of the reasons for using category theory is to get away from set theory. In general, objects in a category don’t have to form sets. The morphisms, however, are elements of sets — the hom-sets. Enriched categories go a step further and replace even those sets with categorical objects. However, it’s not categories all the way down — the base category that’s used for enrichment is still a regular old category with hom-sets.
I’m grateful to Gershom Bazerman for useful comments and to André van Meulebrouck for checking the grammar and spelling.