module Cat.Base where
Precategoriesπ
In univalent mathematics, it makes sense to distinguish two stages in the construction of categories: A precategory is the object that directly corresponds to the definition of precategory as it is traditionally formalised, whereas a category (or univalent category) has an extra condition: Isomorphic objects must be identified.
record Precategory (o h : Level) : Type (lsuc (o β h)) where no-eta-equality
A precategory is a βproof-relevant preorderβ. In a preordered set the inhabitants of a set are related by a proposition which is
- reflexive:
- transitive:
In a precategory, the condition that
be a proposition is relaxed: A precategory has a type of objects
and, between each
a set
of relations (or maps). The name
ββ
is historical and it betrays the original context in which categories
where employed: algebra(ic topology), where the maps in question are
homomorphisms.
field Ob : Type o Hom : Ob β Ob β Type h
Whereas reading a classical definition into a type theory where equality is a proposition, the word set may be read to mean inhabitant of a universe. But in HoTT, if we want categories to be well-behaved, we do actually mean set: A type of h-level 2
field Hom-set : (x y : Ob) β is-set (Hom x y)
If you are already familiar with the definition of precategory there are two things to note here:
First is that our formalization has a family of Hom
-sets rather than a single
Hom
-set and source/target maps.
This formulation is not unique to precategory theory done internally to
type theory, but it is the most reasonable way to formulate things in
this context.
Second is that the word βsetβ in the definition of Hom-set has nothing to do with βsizeβ. Indeed, the βsetβ/βnot a setβ (alternatively βsmallβ/βlargeβ) distinction makes no sense in type theory (some may argue it makes no sense in general).
Instead, the Precategory
record is
parametrised by two levels: o
, and h
. The type
of objects has to fit in the universe Type o
, and the
family of Hom-sets is Type h
valued. As an example, the
thin precategory corresponding to the natural numbers with their usual
ordering would live in Precategory lzero lzero
.
This means, for instance, that there is no single βcategory of setsβ - there is a family of categories of sets, parametrised by the level in which its objects live.
field id : β {x} β Hom x x _β_ : β {x y z} β Hom y z β Hom x y β Hom x z infixr 40 _β_
The βproof-relevantβ version of the reflexivity and transitivity laws
are, respectively, the identity morphisms
and composition of morphisms
.
Unlike in the proof-irrelevant case, in which an inhabitant of
merely witnesses that two things are related, these operations
matter, and thus must satisfy laws:
field idr : β {x y} (f : Hom x y) β f β id β‘ f idl : β {x y} (f : Hom x y) β id β f β‘ f
The two identity laws say that the identity morphisms serve as neutral elements for the composition operation, both on the left and on the right. The associativity law (below) says that both ways of writing parentheses around a composition of three morphisms are equal:
assoc : β {w x y z} (f : Hom y z) (g : Hom x y) (h : Hom w x) β f β (g β h) β‘ (f β g) β h
open hlevel-projection private hom-set : β {o β} (C : Precategory o β) {x y} β is-set (C .Precategory.Hom x y) hom-set C = C .Precategory.Hom-set _ _ instance hlevel-proj-hom : hlevel-projection (quote Precategory.Hom) hlevel-proj-hom .has-level = quote hom-set hlevel-proj-hom .get-level _ = pure (quoteTerm (suc (suc zero))) hlevel-proj-hom .get-argument (_ β· _ β· c vβ· _) = pure c {-# CATCHALL #-} hlevel-proj-hom .get-argument _ = typeError []
Oppositesπ
A common theme throughout precategory theory is that of
duality: The dual of a categorical concept is same concept,
with βall the arrows invertedβ. To make this formal, we introduce the
idea of opposite categories: The opposite of
written
has the same objects
, but with
infixl 60 _^op _^op : β {oβ hβ} β Precategory oβ hβ β Precategory oβ hβ (C ^op) .Precategory.Ob = C .Precategory.Ob (C ^op) .Precategory.Hom x y = C .Precategory.Hom y x (C ^op) .Precategory.Hom-set x y = C .Precategory.Hom-set y x (C ^op) .Precategory.id = C .Precategory.id (C ^op) .Precategory._β_ f g = C .Precategory._β_ g f
Composition in the opposite precategory is βbackwardsβ with respect to This inversion, applied twice, ends up equal to what we started with by the nature of computation - An equality that arises like this, automatically from what Agda computes, is called definitional.
(C ^op) .Precategory.idl x = C .Precategory.idr x (C ^op) .Precategory.idr x = C .Precategory.idl x
The left and right identity laws are swapped for the construction of
the opposite precategory: For idr
one
has to show
which computes into having to show that
The case for idl
is symmetric.
(C ^op) .Precategory.assoc f g h i = C .Precategory.assoc h g f (~ i)
For associativity, consider the case of assoc
for the opposite precategory
What we have to show is - by the type of assocβ
-
This computes into
- which is exactly what sym (assoc C h g f)
shows!
C^op^opβ‘C : β {o β} {C : Precategory o β} β C ^op ^op β‘ C C^op^opβ‘C {C = C} i = precat i where open Precategory precat : C ^op ^op β‘ C precat i .Ob = C .Ob precat i .Hom = C .Hom precat i .Hom-set = C .Hom-set precat i .id = C .id precat i ._β_ = C ._β_ precat i .idr = C .idr precat i .idl = C .idl precat i .assoc = C .assoc
The precategory of Setsπ
Given a universe level, we can
consider the collection of all sets
of that level. This assembles into a precategory
quite nicely, since
taking function types is an operation that preserves
h-level.
module _ where open Precategory Sets : (o : _) β Precategory (lsuc o) o Sets o .Ob = Set o Sets o .Hom A B = β£ A β£ β β£ B β£ Sets o .Hom-set _ B f g p q i j a = B .is-tr (f a) (g a) (happly p a) (happly q a) i j Sets o .id x = x Sets o ._β_ f g x = f (g x) Sets o .idl f = refl Sets o .idr f = refl Sets o .assoc f g h = refl
Functorsπ
record Functor {oβ hβ oβ hβ} (C : Precategory oβ hβ) (D : Precategory oβ hβ) : Type (oβ β hβ β oβ β hβ) where no-eta-equality private module C = Precategory C module D = Precategory D
Since a category is an algebraic structure, there is a natural
definition of homomorphism of categories defined in the same
fashion as, for instance, a homomorphism of groups. Since this
kind of morphism is ubiquitous, it gets a shorter name: Functor
.
Alternatively, functors can be characterised as the βproof-relevant versionβ of a monotone map: A monotone map is a map which preserves the ordering relation, Categorifying, βpreserves the ordering relationβ becomes a function between Hom-sets.
field Fβ : C.Ob β D.Ob Fβ : β {x y} β C.Hom x y β D.Hom (Fβ x) (Fβ y)
A Functor
consists of a function between the object sets
-
and a function between Hom-sets
- which
takes
to
field F-id : β {x} β Fβ (C.id {x}) β‘ D.id F-β : β {x y z} (f : C.Hom y z) (g : C.Hom x y) β Fβ (f C.β g) β‘ Fβ f D.β Fβ g
Furthermore, the morphism mapping
must be homomorphic: Identity morphisms are taken to identity morphisms
(F-id
) and compositions are taken
to compositions (F-β
).
-- Alias for Fβ for use in Functor record modules. β : C.Ob β D.Ob β = Fβ -- Alias for Fβ for use in Functor record modules. β : β {x y} β C.Hom x y β D.Hom (Fβ x) (Fβ y) β = Fβ
Functors also have duals: The opposite of is
op : Functor (C ^op) (D ^op) op .Fβ = Fβ op .Fβ = Fβ op .F-id = F-id op .F-β f g = F-β g f
F^op^opβ‘F : β {o β o' β'} {C : Precategory o β} {D : Precategory o' β'} {F : Functor C D} β Functor.op (Functor.op F) β‘ F F^op^opβ‘F {F = F} i .Functor.Fβ = F .Functor.Fβ F^op^opβ‘F {F = F} i .Functor.Fβ = F .Functor.Fβ F^op^opβ‘F {F = F} i .Functor.F-id = F .Functor.F-id F^op^opβ‘F {F = F} i .Functor.F-β = F .Functor.F-β {-# REWRITE F^op^opβ‘F #-}
Compositionπ
_Fβ_ : β {oβ hβ oβ hβ oβ hβ} {C : Precategory oβ hβ} {D : Precategory oβ hβ} {E : Precategory oβ hβ} β Functor D E β Functor C D β Functor C E _Fβ_ {C = C} {D} {E} F G = comps
Functors, being made up of functions, can themselves be composed. The object mapping of is given by and similarly for the morphism mapping. Alternatively, composition of functors is a categorification of the fact that monotone maps compose.
module Fβ where module C = Precategory C module D = Precategory D module E = Precategory E module F = Functor F module G = Functor G
Fβ : C.Ob β E.Ob Fβ x = F.Fβ (G.Fβ x) Fβ : {x y : C.Ob} β C.Hom x y β E.Hom (Fβ x) (Fβ y) Fβ f = F.Fβ (G.Fβ f)
To verify that the result is functorial, equational reasoning is employed, using the witnesses that and are functorial.
abstract F-id : {x : C.Ob} β Fβ (C.id {x}) β‘ E.id {Fβ x} F-id {x} = F.Fβ (G.Fβ C.id) β‘β¨ ap F.Fβ G.F-id β©β‘ F.Fβ D.id β‘β¨ F.F-id β©β‘ E.id β F-β : {x y z : C.Ob} (f : C.Hom y z) (g : C.Hom x y) β Fβ (f C.β g) β‘ (Fβ f E.β Fβ g) F-β f g = F.Fβ (G.Fβ (f C.β g)) β‘β¨ ap F.Fβ (G.F-β f g) β©β‘ F.Fβ (G.Fβ f D.β G.Fβ g) β‘β¨ F.F-β _ _ β©β‘ Fβ f E.β Fβ g β comps : Functor _ _ comps .Functor.Fβ = Fβ comps .Functor.Fβ = Fβ comps .Functor.F-id = F-id comps .Functor.F-β = F-β
The identity functor can be defined using the identity
function for both its object and morphism mappings. That
functors have an identity and compose would seem to imply that
categories form a category: However, since there is no upper bound on
the h-level of Ob
, we can not form a βcategory of
categoriesβ. If we do impose a bound, however, we can obtain a
category
of strict categories, those which have a set of objects.
Id : β {oβ hβ} {C : Precategory oβ hβ} β Functor C C Id .Functor.Fβ x = x Id .Functor.Fβ f = f Id .Functor.F-id = refl Id .Functor.F-β f g = refl
Natural transformationsπ
Another common theme in category theory is that roughly every concept can be considered the objects of a category. This is the case for functors, as well! The functors between and assemble into a category, notated - the functor category between and
record _=>_ {oβ hβ oβ hβ} {C : Precategory oβ hβ} {D : Precategory oβ hβ} (F G : Functor C D) : Type (oβ β hβ β hβ) where no-eta-equality constructor NT
The morphisms between functors are called natural transformations. A natural transformation can be thought of as a way of turning into that doesnβt involve any βarbitrary choicesβ.
private module F = Functor F module G = Functor G module D = Precategory D module C = Precategory C field Ξ· : (x : _) β D.Hom (F.β x) (G.β x)
The transformation itself is given by Ξ·
, the
family of components, where the component at
is a map
The βwithout arbitrary choicesβ part is encoded in the field is-natural
, which encodes
commutativity of the square below:
is-natural : (x y : _) (f : C.Hom x y) β Ξ· y D.β F.β f β‘ G.β f D.β Ξ· x
Natural transformations also dualise. The opposite of is
op : Functor.op G => Functor.op F op = record { Ξ· = Ξ· ; is-natural = Ξ» x y f β sym (is-natural _ _ f) }
{-# INLINE NT #-} is-natural-transformation : β {o β o' β'} {C : Precategory o β} {D : Precategory o' β'} β (F G : Functor C D) β (Ξ· : β x β D .Precategory.Hom (F .Functor.Fβ x) (G .Functor.Fβ x)) β Type _ is-natural-transformation {C = C} {D = D} F G Ξ· = β x y (f : C .Precategory.Hom x y) β Ξ· y D.β F .Fβ f β‘ G .Fβ f D.β Ξ· x where module D = Precategory D open Functor infixr 30 _Fβ_ infix 20 _=>_ unquoteDecl H-Level-Nat = declare-record-hlevel 2 H-Level-Nat (quote _=>_) module _ {oβ hβ oβ hβ} {C : Precategory oβ hβ} {D : Precategory oβ hβ} {F G : Functor C D} where private module F = Functor F module G = Functor G module D = Precategory D module C = Precategory C open Functor open _=>_
Since the type of natural transformations is defined as a record, we
can not a priori reason about its h-level in a convenient way.
However, using Agdaβs metaprogramming facilities (both reflection
and instance search), we can automatically derive an
equivalence between the type of natural transformations and a certain
type; This type can then be shown to be a set using the standard hlevel
machinery.
opaque Nat-is-set : is-set (F => G) Nat-is-set = hlevel 2
Another fundamental lemma is that equality of natural transformations depends only on equality of the family of morphisms, since being natural is a proposition:
Nat-pathp : {F' G' : Functor C D} β (p : F β‘ F') (q : G β‘ G') β {a : F => G} {b : F' => G'} β (β x β PathP _ (a .Ξ· x) (b .Ξ· x)) β PathP (Ξ» i β p i => q i) a b Nat-pathp p q path i .Ξ· x = path x i Nat-pathp p q {a} {b} path i .is-natural x y f = is-propβpathp (Ξ» i β D.Hom-set _ _ (path y i D.β Functor.Fβ (p i) f) (Functor.Fβ (q i) f D.β path x i)) (a .is-natural x y f) (b .is-natural x y f) i Nat-path : {a b : F => G} β ((x : _) β a .Ξ· x β‘ b .Ξ· x) β a β‘ b Nat-path = Nat-pathp refl refl _Ξ·β_ : β {a b : F => G} β a β‘ b β β x β a .Ξ· x β‘ b .Ξ· x p Ξ·β x = ap (Ξ» e β e .Ξ· x) p _Ξ·α΅_ : β {F' G' : Functor C D} {p : F β‘ F'} {q : G β‘ G'} β {a : F => G} {b : F' => G'} β PathP (Ξ» i β p i => q i) a b β β x β PathP (Ξ» i β D.Hom (p i .Fβ x) (q i .Fβ x)) (a .Ξ· x) (b .Ξ· x) p Ξ·α΅ x = apd (Ξ» i e β e .Ξ· x) p infixl 45 _Ξ·β_
open Precategory open _=>_ instance Underlying-Precategory : β {o β} β Underlying (Precategory o β) Underlying-Precategory = record { β_β = Precategory.Ob } Funlike-Functor : β {o β o' β'} {C : Precategory o β} {D : Precategory o' β'} β Funlike (Functor C D) β C β (Ξ» x β β D β) Funlike-Functor = record { _#_ = Functor.Fβ } Funlike-natural-transformation : β {o β o' β'} {C : Precategory o β} {D : Precategory o' β'} {F G : Functor C D} β Funlike (F => G) β C β (Ξ» x β D .Precategory.Hom (F # x) (G # x)) Funlike-natural-transformation = record { _#_ = _=>_.Ξ· } Extensional-natural-transformation : β {o β o' β' βr} {C : Precategory o β} {D : Precategory o' β'} β {F G : Functor C D} β β¦ sa : {x : β C β} β Extensional (D .Hom (F # x) (G # x)) βr β¦ β Extensional (F => G) (o β βr) Extensional-natural-transformation β¦ sa β¦ .Pathα΅ f g = β i β Pathα΅ sa (f .Ξ· i) (g .Ξ· i) Extensional-natural-transformation β¦ sa β¦ .reflα΅ x i = reflα΅ sa (x .Ξ· i) Extensional-natural-transformation β¦ sa β¦ .idsα΅ .to-path x = Nat-path Ξ» i β sa .idsα΅ .to-path (x i) Extensional-natural-transformation {D = D} β¦ sa β¦ .idsα΅ .to-path-over h = is-propβpathp (Ξ» i β Ξ -is-hlevel 1 Ξ» _ β Pathα΅-is-hlevel 1 sa (hlevel 2)) _ _ _βͺ_β«_ : β {o β o' β'} {C : Precategory o β} {D : Precategory o' β'} β (F : Functor C D) {U V : β C β} β C .Precategory.Hom U V β D .Precategory.Hom (F # U) (F # V) _βͺ_β«_ F f = Functor.Fβ F f