module Cat.CartesianClosed.Free {β} (S : Ξ»-Signature β) where
Free cartesian closed categoriesπ
open Ξ»-Signature S renaming (Ob to Node ; Hom to Edge) data Mor : Ty β Ty β Type β private variable Ο Ο Ο : Ty f g h : Mor Ο Ο infixr 20 _`β_ infixr 19 _`,_
We can define the free Cartesian closed category on a -signature directly as a higher inductive type. The objects of this category will be the simple types over 1, and the morphisms are generated by exactly the operations and equations which go into our definition of Cartesian closed category.
data Mor where `_ : β {x y} β Edge x y β Mor x (` y) `id : Mor Ο Ο _`β_ : Mor Ο Ο β Mor Ο Ο β Mor Ο Ο `idr : f `β `id β‘ f `idl : `id `β f β‘ f `assoc : f `β (g `β h) β‘ (f `β g) `β h `! : Mor Ο `β€ `!-Ξ· : (h : Mor Ο `β€) β `! β‘ h `Οβ : Mor (Ο `Γ Ο) Ο `Οβ : Mor (Ο `Γ Ο) Ο _`,_ : Mor Ο Ο β Mor Ο Ο β Mor Ο (Ο `Γ Ο) `ΟβΞ² : `Οβ `β (f `, g) β‘ f `ΟβΞ² : `Οβ `β (f `, g) β‘ g `ΟΞ· : f β‘ (`Οβ `β f `, `Οβ `β f) `ev : Mor ((Ο `β Ο) `Γ Ο) Ο `Ζ : Mor (Ο `Γ Ο) Ο β Mor Ο (Ο `β Ο) `ΖΞ² : `ev `β (`Ζ f `β `Οβ `, `id `β `Οβ) β‘ f `ΖΞ· : f β‘ `Ζ (`ev `β (f `β `Οβ `, `id `β `Οβ)) squash : is-set (Mor Ο Ο)
We package all of these laws into the appropriate bundles in this <details>
tag.
instance H-Level-Mor : β {x y n} β H-Level (Mor x y) (2 + n) H-Level-Mor = basic-instance 2 squash module _ where open Precategory Free-ccc : Precategory β β Free-ccc .Ob = Ty Free-ccc .Hom = Mor Free-ccc .Hom-set _ _ = squash Free-ccc .id = `id Free-ccc ._β_ = _`β_ Free-ccc .idr _ = `idr Free-ccc .idl _ = `idl Free-ccc .assoc _ _ _ = `assoc open Cartesian-closed open is-exponential open Exponential open is-product open Terminal open Product Free-products : has-products Free-ccc Free-products a b .apex = a `Γ b Free-products a b .Οβ = `Οβ Free-products a b .Οβ = `Οβ Free-products a b .has-is-product .β¨_,_β© f g = f `, g Free-products a b .has-is-product .Οβββ¨β© = `ΟβΞ² Free-products a b .has-is-product .Οβββ¨β© = `ΟβΞ² Free-products a b .has-is-product .unique p q = `ΟΞ· β apβ _`,_ p q Free-terminal : Terminal Free-ccc Free-terminal .top = `β€ Free-terminal .hasβ€ x = contr `! `!-Ξ· open Cartesian-category using (products ; terminal) Free-cartesian : Cartesian-category Free-ccc Free-cartesian .products = Free-products Free-cartesian .terminal = Free-terminal Free-closed : Cartesian-closed Free-ccc Free-cartesian Free-closed .has-exp A B .B^A = A `β B Free-closed .has-exp A B .ev = `ev Free-closed .has-exp A B .has-is-exp .Ζ = `Ζ Free-closed .has-exp A B .has-is-exp .commutes m = `ΖΞ² Free-closed .has-exp A B .has-is-exp .unique m' x = `ΖΞ· β ap `Ζ x private module Syn = Cartesian-category Free-cartesian module Synα΅ = Monoidal-category (Cartesian-monoidal Free-cartesian)
Instead of phrasing the universal property as a form of initiality, weβll state induction instead. While we could derive induction from initiality, stating the βtraditionalβ universal property for a free CCC, this has a couple of issues when it comes to working in a homotopical proof assistant.
Firstly, the categories weβre using for the normalisation proof are
not strict, so we do not have a
proper 1-category of models within which we could say that Free-ccc
is initial. Even then, it is slightly
unreasonable to expect Cartesian closed functors to preserve the
structure up to identity.
We could set up a bicategory of Cartesian closed
categories, functors, and natural transformations between them, but this
would result in a significantly more annoying normalisation result,
saying that every Mor
phism is
isomorphic to the inclusion of a normal form.
Conversely, if we did require all the categories involved to be
strict (which would require exchanging the presheaf category for
something like a material set-valued presheaf category),
having normal forms that live in types identical to the inputs
is still not good enough, because now we either end up with a normal
form that is only related to the input over a PathP
, or we introduce a
subst
that would not
compute in a useful way.
Stating an induction principle for Ty
and Mor
is simply a much more
sensible thing to do: we do not impose a strictness condition on the
categories weβre eliminating into by requiring models to live in a
1-category, and now the types guarantee that the results are
definitionally talking about the input types. However, since
Mor
has
quite a few constructors, the inputs to this induction
principle are⦠quite gnarly. We package them up using the language of displayed categories.
First, we require a displayed category
which gives us not only the motives for elimination, i.e.Β the
types of the conclusions, but also the methods (including the
equational methods) for `id
and _`β_
.
module elim {o' β'} {D : Displayed Free-ccc o' β'}
Next, must have total products over the Cartesian structure of In non-displayed language, this says that the total category has products and the projection functor preserves them. But in displayed language, it says precisely that we can put together product diagrams in which are displayed over product diagrams in We also ask for a total terminal object in
(cart : Cartesian-over D Free-cartesian)
This makes
into a Cartesian category over
which in turn enables us to talk about total exponential objects in
Of course, these also provide methods weβre lacking, so we must also ask
for these, making
into a category Cartesian closed over
Finally, we can ask for an interpretation
of the base types in
(cco : Cartesian-closed-over D cart Free-closed) (f : (x : Node) β D Κ» (` x)) where
open Cartesian-closed-over D cart {Free-closed} cco open Cat.Displayed.Reasoning D open Cartesian-over cart
This lets us construct a section of the objects of i.e.Β a method that turns any type into an object
Ty-elim : (x : Ty) β D Κ» x Ty-elim `β€ = top' Ty-elim (` x) = f x Ty-elim (Ο `Γ Ο) = Ty-elim Ο ββ' Ty-elim Ο Ty-elim (Ο `β Ο) = [ Ty-elim Ο , Ty-elim Ο ]'
Since the base terms in a
have an arbitrary Ty
as input (but a base type
as output), we can only state the type of our last method after defining
Ty-elim
.
This type is, however, natural: we ask for a map
lying over every basic term
base-method : Type _
base-method = β {x y} (e : Edge x y) β Hom[ ` e ] (Ty-elim x) (f y)
private module _ (h : base-method) where
go : β {x y} (m : Mor x y) β Hom[ m ] (Ty-elim x) (Ty-elim y)
By a long and uninteresting case bash, we can extend base-method
to cover all
of Mor
.
Ty
as input (but a base type
as output), we can only state the type of our last method after defining
Ty-elim
.
This type is, however, natural: we ask for a map
lying over every basic term
go (` x) = h x go `id = id' go (f `β g) = go f β' go g go (`idr {f = f} i) = idr' (go f) i go (`idl {f = f} i) = idl' (go f) i go (`assoc {f = f} {g = g} {h = h} i) = assoc' (go f) (go g) (go h) i go `! = !' go (`!-Ξ· e i) = !'-uniqueβ {h = !'} {h' = go e} {p = `!-Ξ· e} i go `Οβ = Οβ' go `Οβ = Οβ' go (f `, g) = β¨ go f , go g β©' go (`ΟβΞ² {f = f} {g = g} i) = Οβββ¨β©' {f' = go f} {g' = go g} i go (`ΟβΞ² {f = f} {g = g} i) = Οβββ¨β©' {f' = go f} {g' = go g} i go `ev = ev' go (`Ζ e) = Ζ' (go e)
Note that the following equational cases need slight corrections
(which we are free to do because Mor
is a set) between the path
constructors in Mor
and the
laws required for a Cartesian closed category.
go (`ΟΞ· {f = f} i) = want i where have : PathP (Ξ» i β Hom[ Syn.β¨β©-unique refl refl i ] _ _) (go f) β¨ Οβ' β' go f , Οβ' β' go f β©' have = β¨β©'-unique {other' = go f} refl refl want : PathP (Ξ» i β Hom[ `ΟΞ· i ] _ _) (go f) β¨ Οβ' β' go f , Οβ' β' go f β©' want = cast[] have go (`ΖΞ² {f = f} i) = want i where want : PathP (Ξ» i β Hom[ `ΖΞ² {f = f} i ] _ _) (ev' β' β¨ Ζ' (go f) β' Οβ' , id' β' Οβ' β©') (go f) want = cast[] (commutes' (go f)) go (`ΖΞ· {f = f} i) = want i where want : PathP (Ξ» i β Hom[ `ΖΞ· {f = f} i ] _ _) (go f) (Ζ' (ev' β' β¨ go f β' Οβ' , id' β' Οβ' β©')) want = cast[] (Ζ'-unique {p = refl} (go f) refl) go (squash x y p q i j) = is-setβsquarep (Ξ» i j β Hom[ squash x y p q i j ]-set (Ty-elim _) (Ty-elim _)) (Ξ» i β go x) (Ξ» i β go (p i)) (Ξ» i β go (q i)) (Ξ» i β go y) i j open Section
Induction for Free-ccc
says that, if we
have such a βdisplayed Cartesian closed categoryβ
and interpretations of the base types and base terms, then
has a section.
Free-ccc-elim : base-method β Section D Free-ccc-elim h .Sβ = Ty-elim Free-ccc-elim h .Sβ = go h Free-ccc-elim h .S-id = refl Free-ccc-elim h .S-β f g = refl
We can recover a more traditional initiality result for Free-ccc
by following the general pattern for deriving initiality
from induction. Specifically, if
is a (non-displayed) Cartesian closed category, then the chaotic bifibration
provides the βgenericβ inputs to our induction principle, and supposing
we additionally have a model of
in
the resulting section is exactly a Cartesian closed functor
This proves weak initiality.
To prove uniqueness, supposing we have some other Cartesian closed functor we would define a category over where the objects over are isomorphisms and the βmorphismβ over is the naturality square Cartesian closure of would provide the data necessary for the displayed Cartesian closed structure. Then, assuming agrees with on base types and terms (i.e., it picks out the same in the section of over objects is then a family of isomorphisms and the section over morphisms is exactly naturality for this family.
As mentioned above, without an additional assumption that is also a strict category, and that preserves the Cartesian closed structure up to identity, this βpseudoβ, or bicategorical initiality is the best we can do.
Intensional syntaxπ
Our objective is to prove that, if both the base types and base terms
in the lambda-signature
have decidable equality, then so do the objects and morphisms in
As Mor
is a
complicated higher-inductive type, this is essentially infeasible to do
βby handβ by a case bash, which works for ordinary indexed inductive
types because those have all disjoint constructors.
The strategy will instead be to show that Mor
is equivalent to some
type that we can write a case bash for. That is, weβll write a
sound normalisation procedure for Mor
, which (by construction)
factors through some type that has decidable equality.2 Note that since Mor
is a
quotient, and our normalisation procedure is a function, completeness is
automatic.
Factoring the construction through some intermediate type of normal
forms is also necessary to actually state normalisation to begin with:
soundness and completeness together imply that, if normalisation were
just an endofunction on Mor
, it would be the
identity.
Our notion of normal form is that of the simply-typed lambda
calculus. Note that despite Mor
working over
types, we will introduce a notion of context to be
used during the proof of normalisation. The normal form of a map
will then live in
i.e.Β it will inhabit the context with a single variable typed the domain
of
This is because normalisation for function types will involve
renamings, and implementing this correctly is easier if binders
are separate from products. Since weβre working with simple types,
contexts are just lists of types. We also have the usual definition of
variable as a pointer into a nonempty context.
data Cx : Type β where β : Cx _,_ : Cx β Ty β Cx private variable Ξ Ξ Ξ : Cx data Var : Cx β Ty β Type β where stop : Var (Ξ , Ο) Ο pop : Var Ξ Ο β Var (Ξ , Ο) Ο
The type of normal forms has a unique constructor for each type,3 and the arguments are essentially unsurprising in each case: Thereβs nothing to a normal form of the unit type, and a normal pair is a pair of normal forms. For function types, we shift the domain into the context. At base types, the normal forms are given by neutral terms.
data Nf where lam : Nf (Ξ , Ο) Ο β Nf Ξ (Ο `β Ο) pair : Nf Ξ Ο β Nf Ξ Ο β Nf Ξ (Ο `Γ Ο) unit : Nf Ξ `β€ ne : β {x} β Ne Ξ (` x) β Nf Ξ (` x)
A neutral term is a variable, or an elimination form applied to another neutral. The βelimination formβ for a base term is also application to a normal form in the domain. For example, we can build a neutral of type by projecting the first component from a neutral of type
data Ne where var : Var Ξ Ο β Ne Ξ Ο app : Ne Ξ (Ο `β Ο) β Nf Ξ Ο β Ne Ξ Ο hom : β {a b} β Edge a b β Nf Ξ a β Ne Ξ (` b) fstβ : Ne Ξ (Ο `Γ Ο) β Ne Ξ Ο sndβ : Ne Ξ (Ο `Γ Ο) β Ne Ξ Ο
We summarize neutrals and normals with a selection of some of our finest βgammas and turnstilesβ, eliding the translation4 from named variables in the context (i.e.Β the judgement to de Bruijn indices.
Normalisation and presheavesπ
The key idea behind our normalisation algorithm, following ΔubriΔ et. al. (1998), is to work in a category of presheaves over the syntax which are a model of the same with the interpretation of base types (and terms) given by the Yoneda embedding We thus have a (Cartesian closed) functor arising from initiality, which is defined in terms of the Cartesian closed structure of i.e.Β we have the following (definitional) computation rules.
The elements of thus do not correspond directly to morphisms in the base, but are instead a sort of interaction representation of Now since the Yoneda embedding is a Cartesian closed functor, the universal property of gives a natural isomorphism Intensionally, round-tripping through this isomorphism has the effect of replacing a map by its normal form, which can be noticed because (e.g.) the elements of are actual pairs. However, we can not observe this happening mathematically because, as mentioned above, a map and its normal form in are identical.
We would like to factor this isomorphism through Nf
above,
but Nf
is not
readily made into a presheaf on the entire syntax. We instead pass to
presheaves on a subcategory of the syntax where we can easily
internalise Nf
and Ne
: the
renamings, the smallest subcategory of
which is closed under precomposition by
and under the functorial action
which is of course best defined as the inductive type Ren
,
which we use as the type of morphisms for the category Rens
.
data Ren : Cx β Cx β Type β where stop : Ren Ξ Ξ drop : Ren Ξ Ξ β Ren (Ξ , Ο) Ξ keep : Ren Ξ Ξ β Ren (Ξ , Ο) (Ξ , Ο)
There is an evident embedding of back into written out below, by interpreting the constructors as the aforementioned categorical constructions (and contexts by products). Moreover, this embedding is a Cartesian functor.
β¦_β§αΆ : Cx β Ty β¦ β β§αΆ = `β€ β¦ Ξ , x β§αΆ = β¦ Ξ β§αΆ `Γ x β¦_β§Κ³ : Ren Ξ Ξ β Mor β¦ Ξ β§αΆ β¦ Ξ β§αΆ β¦ stop β§Κ³ = `id β¦ drop r β§Κ³ = β¦ r β§Κ³ `β `Οβ β¦ keep r β§Κ³ = β¦ r β§Κ³ `β `Οβ `, `Οβ
We then have to prove that all of these constructions are sets, since we will be
using them to form precategories and presheaves. This is bog-standard
encode-decode stuff, and so itβs uncommented in this <details>
block for space.
While weβre here, we also prove that all these type formers preserve
decidability of equality.
<details>
block for space.private same-cx : Cx β Cx β Prop β same-cx β β = el! (Lift _ β€) same-cx β _ = el! (Lift _ β₯) same-cx (Ξ , Ο) (Ξ , Ο) = el! (β same-cx Ξ Ξ β Γ β same-ty Ο Ο β) same-cx (Ξ , Ο) _ = el! (Lift _ β₯) from-same-cx : β Ξ Ξ' β β same-cx Ξ Ξ' β β Ξ β‘ Ξ' from-same-cx β β p = refl from-same-cx (Ξ , x) (Ξ' , y) p = apβ _,_ (from-same-cx Ξ Ξ' (p .fst)) (from-same-ty x y (p .snd)) refl-same-cx : β Ξ β β same-cx Ξ Ξ β refl-same-cx β = lift tt refl-same-cx (Ξ , x) = (refl-same-cx Ξ) , (refl-same-ty x) instance H-Level-Cx : β {n} β H-Level Cx (2 + n) H-Level-Cx = basic-instance 2 $ set-identity-systemβhlevel (Ξ» x y β β same-cx x y β) refl-same-cx (Ξ» x y β hlevel 1) from-same-cx private same-ren : β {Ξ' Ξ'} (p : β same-cx Ξ Ξ' β) (q : β same-cx Ξ Ξ' β) β Ren Ξ Ξ β Ren Ξ' Ξ' β Prop β same-ren p q stop stop = el! (Lift _ β€) same-ren p q (drop x) (drop y) = same-ren (p .fst) q x y same-ren p q (keep x) (keep y) = same-ren (p .fst) (q .fst) x y same-ren p q stop (drop y) = el! (Lift _ β₯) same-ren p q stop (keep y) = el! (Lift _ β₯) same-ren p q (drop x) stop = el! (Lift _ β₯) same-ren p q (drop x) (keep y) = el! (Lift _ β₯) same-ren p q (keep x) stop = el! (Lift _ β₯) same-ren p q (keep x) (drop y) = el! (Lift _ β₯) from-same-ren : β {Ξ Ξ Ξ' Ξ'} (p : β same-cx Ξ Ξ' β) (q : β same-cx Ξ Ξ' β) x y β β same-ren p q x y β β PathP (Ξ» i β Ren (from-same-cx Ξ Ξ' p i) (from-same-cx Ξ Ξ' q i)) x y from-same-ren {Ξ = Ξ} {Ξ' = Ξ'} p q stop stop Ξ± = is-setβcast-pathp {x = Ξ , Ξ} {y = Ξ' , Ξ'} {from-same-cx _ _ p ,β _} {_ ,β _} (uncurry Ren) (hlevel 2) Ξ» i β stop from-same-ren p q (drop x) (drop y) Ξ± = Ξ» i β drop (from-same-ren _ _ x y Ξ± i) from-same-ren {Ξ , Ο} {Ξ , Ο} {Ξ' , Ο'} {Ξ' , Ο'} p q (keep x) (keep y) Ξ± = is-setβcast-pathp {x = _} {y = _} {from-same-cx _ _ (p .fst , q .snd) ,β from-same-cx (Ξ , Ο) (Ξ' , Ο') q} {_ ,β _} (uncurry Ren) (hlevel 2) Ξ» i β keep (from-same-ren _ _ x y Ξ± i) refl-same-ren : β {Ξ Ξ} (x : Ren Ξ Ξ) β β same-ren (refl-same-cx Ξ) (refl-same-cx Ξ) x x β refl-same-ren stop = lift tt refl-same-ren (drop x) = refl-same-ren x refl-same-ren (keep x) = refl-same-ren x same-var : β {Ξ' Ο'} β β same-cx Ξ Ξ' β β β same-ty Ο Ο' β β Var Ξ Ο β Var Ξ' Ο' β Prop β same-var q p stop stop = el! (Lift _ β€) same-var q p stop _ = el! (Lift _ β₯) same-var q p (pop x) (pop y) = same-var (q .fst) p x y same-var q p (pop x) _ = el! (Lift _ β₯) from-same-var : β {Ξ' Ο'} (p : β same-cx Ξ Ξ' β) (q : β same-ty Ο Ο' β) x y β β same-var p q x y β β PathP (Ξ» i β Var (from-same-cx Ξ Ξ' p i) (from-same-ty Ο Ο' q i)) x y from-same-var {Ξ = Ξ , Ο} {Ο = Ο} {Ξ' , Ο'} {Ο'} p q stop stop Ξ± = subst (Ξ» e β PathP (Ξ» i β Var (from-same-cx Ξ Ξ' (p .fst) i , from-same-ty Ο Ο' (p .snd) i) (from-same-ty Ο Ο' e i)) stop stop) {x = p .snd} {y = q} prop! Ξ» i β stop from-same-var p q (pop x) (pop y) Ξ± = Ξ» i β Var.pop (from-same-var (p .fst) q x y Ξ± i) same-ne : β {Ξ' Ο'} β β same-cx Ξ Ξ' β β β same-ty Ο Ο' β β Ne Ξ Ο β Ne Ξ' Ο' β Prop β same-nf : β {Ξ' Ο'} β β same-cx Ξ Ξ' β β β same-ty Ο Ο' β β Nf Ξ Ο β Nf Ξ' Ο' β Prop β same-nf q p unit unit = el! (Lift _ β€) same-nf q p unit _ = el! (Lift _ β₯) same-nf q p (lam x) (lam y) = same-nf (q , p .fst) (p .snd) x y same-nf q p (lam x) _ = el! (Lift _ β₯) same-nf q p (pair a b) (pair x y) = el! (β same-nf q (p .fst) a x β Γ β same-nf q (p .snd) b y β) same-nf q p (pair a b) _ = el! (Lift _ β₯) same-nf q p (ne x) (ne y) = same-ne q p x y same-nf q p (ne x) _ = el! (Lift _ β₯) same-ne {Ξ = Ξ} {Ο = Ο} {Ξ'} {Ο'} q p (var x) (var y) = same-var q p x y same-ne _ _ (var x) _ = el! (Lift _ β₯) same-ne {Ξ = Ξ} q p (app {Ο = Ο} f x) (app {Ο = Ο} g y) = el! ( Ξ£[ r β same-ty Ο Ο ] (β same-ne q (r , p) f g β Γ β same-nf q r x y β)) same-ne _ _ (app f x) _ = el! (Lift _ β₯) same-ne q p (fstβ {Ο = Ο} x) (fstβ {Ο = Ο} y) = el! ( Ξ£[ r β same-ty Ο Ο ] β same-ne q (p , r) x y β) same-ne _ _ (fstβ x) _ = el! (Lift _ β₯) same-ne q p (sndβ {Ο = Ο} x) (sndβ {Ο = Ο} y) = el! ( Ξ£[ r β same-ty Ο Ο ] β same-ne q (r , p) x y β) same-ne _ _ (sndβ x) _ = el! (Lift _ β₯) same-ne q p (hom {a = Ο} x a) (hom {a = Ο} y b) = el! ( Ξ£[ r β same-ty Ο Ο ] ( PathP (Ξ» i β Edge (from-same-ty Ο Ο r i) (p i)) x y Γ β same-nf q r a b β )) same-ne _ _ (hom x a) _ = el! (Lift _ β₯) from-same-ne : β {Ξ' Ο'} (p : β same-cx Ξ Ξ' β) (q : β same-ty Ο Ο' β) x y β β same-ne p q x y β β PathP (Ξ» i β Ne (from-same-cx Ξ Ξ' p i) (from-same-ty Ο Ο' q i)) x y from-same-nf : β {Ξ' Ο'} (p : β same-cx Ξ Ξ' β) (q : β same-ty Ο Ο' β) x y β β same-nf p q x y β β PathP (Ξ» i β Nf (from-same-cx Ξ Ξ' p i) (from-same-ty Ο Ο' q i)) x y from-same-ne p q (var x) (var y) Ξ± = Ξ» i β var (from-same-var _ _ x y Ξ± i) from-same-ne p q (app f x) (app g y) Ξ± = Ξ» i β app (from-same-ne _ _ f g (Ξ± .snd .fst) i) (from-same-nf _ _ x y (Ξ± .snd .snd) i) from-same-ne p q (fstβ x) (fstβ y) Ξ± = Ξ» i β fstβ (from-same-ne _ _ x y (Ξ± .snd) i) from-same-ne p q (sndβ x) (sndβ y) Ξ± = Ξ» i β sndβ (from-same-ne _ _ x y (Ξ± .snd) i) from-same-ne p q (hom f x) (hom g y) Ξ± = Ξ» i β hom (Ξ± .snd .fst i) (from-same-nf _ _ x y (Ξ± .snd .snd) i) from-same-nf p q (lam x) (lam y) Ξ± = Ξ» i β lam (from-same-nf _ _ x y Ξ± i) from-same-nf p q (pair a b) (pair x y) Ξ± = Ξ» i β pair (from-same-nf _ _ a x (Ξ± .fst) i) (from-same-nf _ _ b y (Ξ± .snd) i) from-same-nf p q unit unit Ξ± = Ξ» i β unit from-same-nf p q (ne x) (ne y) Ξ± = Ξ» i β ne (from-same-ne p q x y Ξ± i) refl-same-var : (v : Var Ξ Ο) β β same-var (refl-same-cx Ξ) (refl-same-ty Ο) v v β refl-same-var stop = lift tt refl-same-var (pop v) = refl-same-var v refl-same-ne : (v : Ne Ξ Ο) β β same-ne (refl-same-cx Ξ) (refl-same-ty Ο) v v β refl-same-nf : (v : Nf Ξ Ο) β β same-nf (refl-same-cx Ξ) (refl-same-ty Ο) v v β refl-same-ne (var x) = refl-same-var x refl-same-ne (app {Ο = Ο} v x) = refl-same-ty Ο , refl-same-ne v , refl-same-nf x refl-same-ne (fstβ {Ο = Ο} v) = refl-same-ty Ο , refl-same-ne v refl-same-ne (sndβ {Ο = Ο} v) = refl-same-ty Ο , refl-same-ne v refl-same-ne (hom {a = Ο} x v) = refl-same-ty Ο , is-setβcast-pathp {p = refl} {q = from-same-ty Ο Ο (refl-same-ty Ο)} (Ξ» e β Edge e _) (hlevel 2) refl , refl-same-nf v refl-same-nf (lam x) = refl-same-nf x refl-same-nf (pair a b) = refl-same-nf a , refl-same-nf b refl-same-nf unit = lift tt refl-same-nf (ne x) = refl-same-ne x from-same-var' : (x y : Var Ξ Ο) β β same-var (refl-same-cx Ξ) (refl-same-ty Ο) x y β β x β‘ y from-same-var' {Ξ} {Ο} x y p = is-setβcast-pathp {x = Ξ , Ο} {y = Ξ , Ο} {_ ,β _} {refl} (uncurry Var) (hlevel 2) (from-same-var (refl-same-cx Ξ) (refl-same-ty Ο) x y p) from-same-nf' : (x y : Nf Ξ Ο) β β same-nf (refl-same-cx Ξ) (refl-same-ty Ο) x y β β x β‘ y from-same-nf' {Ξ} {Ο} x y p = is-setβcast-pathp {x = Ξ , Ο} {y = Ξ , Ο} {_ ,β _} {refl} (uncurry Nf) (hlevel 2) (from-same-nf (refl-same-cx Ξ) (refl-same-ty Ο) x y p) from-same-ne' : (x y : Ne Ξ Ο) β β same-ne (refl-same-cx Ξ) (refl-same-ty Ο) x y β β x β‘ y from-same-ne' {Ξ} {Ο} x y p = is-setβcast-pathp {x = Ξ , Ο} {y = Ξ , Ο} {_ ,β _} {refl} (uncurry Ne) (hlevel 2) (from-same-ne (refl-same-cx Ξ) (refl-same-ty Ο) x y p) instance H-Level-Ren : β {n} β H-Level (Ren Ξ Ξ) (2 + n) H-Level-Ren {Ξ} {Ξ} = basic-instance 2 $ set-identity-systemβhlevel (Ξ» x y β β same-ren (refl-same-cx Ξ) (refl-same-cx Ξ) x y β) refl-same-ren (Ξ» x y β hlevel 1) (Ξ» x y p β is-setβcast-pathp {x = Ξ , Ξ} {y = Ξ , Ξ} {_ ,β _} {refl} (uncurry Ren) (hlevel 2) (from-same-ren (refl-same-cx Ξ) (refl-same-cx Ξ) x y p)) H-Level-Var : β {n} β H-Level (Var Ξ Ο) (2 + n) H-Level-Var {Ξ} {Ο} = basic-instance 2 $ set-identity-systemβhlevel (Ξ» x y β β same-var (refl-same-cx Ξ) (refl-same-ty Ο) x y β) refl-same-var (Ξ» x y β hlevel 1) from-same-var' H-Level-Nf : β {n} β H-Level (Nf Ξ Ο) (2 + n) H-Level-Nf {Ξ} {Ο} = basic-instance 2 $ set-identity-systemβhlevel (Ξ» x y β β same-nf (refl-same-cx Ξ) (refl-same-ty Ο) x y β) refl-same-nf (Ξ» x y β hlevel 1) from-same-nf' H-Level-Ne : β {n} β H-Level (Ne Ξ Ο) (2 + n) H-Level-Ne {Ξ} {Ο} = basic-instance 2 $ set-identity-systemβhlevel (Ξ» x y β β same-ne (refl-same-cx Ξ) (refl-same-ty Ο) x y β) refl-same-ne (Ξ» x y β hlevel 1) from-same-ne' module _ β¦ _ : Discrete Node β¦ β¦ _ : β {x y} β Discrete (Edge x y) β¦ where private dec-same-ty : β Ο Ο β Dec β same-ty Ο Ο β dec-same-ty `β€ Ο with Ο ... | `β€ = yes (lift tt) ... | ` x = no Ξ» () ... | x `Γ y = no Ξ» () ... | x `β y = no Ξ» () dec-same-ty (` x) Ο with Ο ... | ` y = auto ... | `β€ = no Ξ» () ... | x `Γ y = no Ξ» () ... | x `β y = no Ξ» () dec-same-ty (a `Γ b) Ο with Ο ... | x `Γ y = Dec-Γ β¦ dec-same-ty a x β¦ β¦ dec-same-ty b y β¦ ... | `β€ = no Ξ» () ... | ` y = no Ξ» () ... | x `β y = no Ξ» () dec-same-ty (a `β b) Ο with Ο ... | x `β y = Dec-Γ β¦ dec-same-ty a x β¦ β¦ dec-same-ty b y β¦ ... | `β€ = no Ξ» () ... | ` y = no Ξ» () ... | x `Γ y = no Ξ» () dec-same-var : β {Ξ Ο Ξ' Ο'} β (Ξ± : β same-cx Ξ Ξ' β) β (Ξ² : β same-ty Ο Ο' β) β (x : Var Ξ Ο) (y : Var Ξ' Ο') β Dec β same-var Ξ± Ξ² x y β dec-same-var Ξ± Ξ² stop y with y ... | stop = yes (lift tt) ... | pop _ = no Ξ» () dec-same-var Ξ± Ξ² (pop x) y with y ... | pop y = dec-same-var (Ξ± .fst) Ξ² x y ... | stop = no Ξ» () dec-same-ne : β {Ξ Ο Ξ' Ο'} β (Ξ± : β same-cx Ξ Ξ' β) β (Ξ² : β same-ty Ο Ο' β) β (x : Ne Ξ Ο) (y : Ne Ξ' Ο') β Dec β same-ne Ξ± Ξ² x y β dec-same-nf : β {Ξ Ο Ξ' Ο'} β (Ξ± : β same-cx Ξ Ξ' β) β (Ξ² : β same-ty Ο Ο' β) β (x : Nf Ξ Ο) (y : Nf Ξ' Ο') β Dec β same-nf Ξ± Ξ² x y β dec-same-nf Ξ± Ξ² (lam x) (lam y) = dec-same-nf (Ξ± , Ξ² .fst) (Ξ² .snd) x y dec-same-nf Ξ± Ξ² (pair a b) (pair x y) = Dec-Γ β¦ dec-same-nf Ξ± (Ξ² .fst) a x β¦ β¦ dec-same-nf Ξ± (Ξ² .snd) b y β¦ dec-same-nf Ξ± Ξ² unit unit = yes (lift tt) dec-same-nf Ξ± Ξ² (ne x) (ne y) = dec-same-ne Ξ± Ξ² x y dec-same-ne Ξ± Ξ² (var x) y with y ... | var y = dec-same-var Ξ± Ξ² x y ... | app _ _ = no Ξ» () ... | fstβ _ = no Ξ» () ... | sndβ _ = no Ξ» () ... | hom _ _ = no Ξ» () dec-same-ne Ξ± Ξ² (app {Ο = Ο} f x) y with y ... | app {Ο = Ο} g y = Dec-Ξ£ (hlevel 1) (dec-same-ty Ο Ο) Ξ» Ξ³ β Dec-Γ β¦ dec-same-ne Ξ± (Ξ³ , Ξ²) f g β¦ β¦ dec-same-nf Ξ± Ξ³ x y β¦ ... | var _ = no Ξ» () ... | fstβ _ = no Ξ» () ... | sndβ _ = no Ξ» () ... | hom _ _ = no Ξ» () dec-same-ne Ξ± Ξ² (hom {a = a} f x) y with y ... | hom {a = b} g y = Dec-Ξ£ (hlevel 1) (dec-same-ty a b) Ξ» Ξ³ β Dec-Γ β¦ invmap to-pathp from-pathp auto β¦ β¦ dec-same-nf Ξ± Ξ³ x y β¦ ... | var _ = no Ξ» () ... | app _ _ = no Ξ» () ... | fstβ _ = no Ξ» () ... | sndβ _ = no Ξ» () dec-same-ne Ξ± Ξ² (fstβ {Ο = Ο} x) y with y ... | fstβ {Ο = Ο} y = Dec-Ξ£ (hlevel 1) (dec-same-ty Ο Ο) Ξ» Ξ³ β dec-same-ne Ξ± (Ξ² , Ξ³) x y ... | var _ = no Ξ» () ... | app _ _ = no Ξ» () ... | sndβ _ = no Ξ» () ... | hom _ _ = no Ξ» () dec-same-ne Ξ± Ξ² (sndβ {Ο = Ο} x) y with y ... | sndβ {Ο = Ο} y = Dec-Ξ£ (hlevel 1) (dec-same-ty Ο Ο) Ξ» Ξ³ β dec-same-ne Ξ± (Ξ³ , Ξ²) x y ... | var _ = no Ξ» () ... | app _ _ = no Ξ» () ... | fstβ _ = no Ξ» () ... | hom _ _ = no Ξ» () instance Discrete-Ty : Discrete Ty Discrete-Ty .decide x y = invmap (from-same-ty x y) (Ξ» p β subst (Ξ» e β β same-ty x e β) p (refl-same-ty x)) (dec-same-ty x y) Discrete-Var : β {Ξ Ο} β Discrete (Var Ξ Ο) Discrete-Var {Ξ} {Ο} .decide x y = invmap (from-same-var' x y) (Ξ» p β subst (Ξ» e β β same-var (refl-same-cx Ξ) (refl-same-ty Ο) x e β) p (refl-same-var x)) (dec-same-var (refl-same-cx Ξ) (refl-same-ty Ο) x y) Discrete-Ne : β {Ξ Ο} β Discrete (Ne Ξ Ο) Discrete-Ne {Ξ} {Ο} .decide x y = invmap (from-same-ne' x y) (Ξ» p β subst (Ξ» e β β same-ne (refl-same-cx Ξ) (refl-same-ty Ο) x e β) p (refl-same-ne x)) (dec-same-ne (refl-same-cx Ξ) (refl-same-ty Ο) x y) Discrete-Nf : β {Ξ Ο} β Discrete (Nf Ξ Ο) Discrete-Nf {Ξ} {Ο} .decide x y = invmap (from-same-nf' x y) (Ξ» p β subst (Ξ» e β β same-nf (refl-same-cx Ξ) (refl-same-ty Ο) x e β) p (refl-same-nf x)) (dec-same-nf (refl-same-cx Ξ) (refl-same-ty Ο) x y)
Of course, we also have embeddings from variables, neutrals and
normals back into the syntax, which we will continue to write using
decorated βsemantic bracketsβ β¦_β§
.
β¦_β§βΏ : Var Ξ Ο β Mor β¦ Ξ β§αΆ Ο
β¦_β§β : Nf Ξ Ο β Mor β¦ Ξ β§αΆ Ο
β¦_β§β : Ne Ξ Ο β Mor β¦ Ξ β§αΆ Ο
Due to a paucity of letters and unicode sub/superscripts, we went with
superscript β¦_β§βΏ
for βnameβ
interpreting variables, and subscript β¦_β§β
for βstuckβ
interpreting neutrals.
β¦_β§
.β¦ stop β§βΏ = `Οβ β¦ pop x β§βΏ = β¦ x β§βΏ `β `Οβ β¦ lam h β§β = `Ζ β¦ h β§β β¦ pair a b β§β = β¦ a β§β `, β¦ b β§β β¦ ne x β§β = β¦ x β§β β¦ unit β§β = `! β¦ var x β§β = β¦ x β§βΏ β¦ app f x β§β = `ev `β (β¦ f β§β `, β¦ x β§β) β¦ fstβ h β§β = `Οβ `β β¦ h β§β β¦ sndβ h β§β = `Οβ `β β¦ h β§β β¦ hom s h β§β = (` s) `β β¦ h β§β
Next, we equip renamings with the structure of a category; variables,
neutrals and normals get the structure of presheaves over the category
of renamings.
_βΚ³_ : β {Ξ Ξ Ξ} β Ren Ξ Ξ β Ren Ξ Ξ β Ren Ξ Ξ
ren-var : β {Ξ Ξ Ο} β Ren Ξ Ξ β Var Ξ Ο β Var Ξ Ο
ren-ne : β {Ξ Ξ Ο} β Ren Ξ Ξ β Ne Ξ Ο β Ne Ξ Ο
ren-nf : β {Ξ Ξ Ο} β Ren Ξ Ξ β Nf Ξ Ο β Nf Ξ Ο
As is becoming traditional, the implementation is hidden in this <details>
block, and the verification of the myriad equational laws is omitted
from the page entirely. Many cases were bashed in the making of this
module.
stop βΚ³ Ο = Ο drop Ο βΚ³ Ο = drop (Ο βΚ³ Ο) keep Ο βΚ³ stop = keep Ο keep Ο βΚ³ drop Ο = drop (Ο βΚ³ Ο) keep Ο βΚ³ keep Ο = keep (Ο βΚ³ Ο) ren-var stop v = v ren-var (drop Ο) v = pop (ren-var Ο v) ren-var (keep Ο) stop = stop ren-var (keep Ο) (pop v) = pop (ren-var Ο v) ren-ne Ο (var v) = var (ren-var Ο v) ren-ne Ο (app f a) = app (ren-ne Ο f) (ren-nf Ο a) ren-ne Ο (fstβ a) = fstβ (ren-ne Ο a) ren-ne Ο (sndβ a) = sndβ (ren-ne Ο a) ren-ne Ο (hom s a) = hom s (ren-nf Ο a) ren-nf Ο (lam n) = lam (ren-nf (keep Ο) n) ren-nf Ο (pair a b) = pair (ren-nf Ο a) (ren-nf Ο b) ren-nf Ο (ne x) = ne (ren-ne Ο x) ren-nf Ο unit = unit
βΚ³-idr : (Ο : Ren Ξ Ξ) β Ο βΚ³ stop β‘ Ο βΚ³-idr stop = refl βΚ³-idr (drop Ο) = ap drop (βΚ³-idr Ο) βΚ³-idr (keep Ο) = refl βΚ³-assoc : β {w x y z} (f : Ren y z) (g : Ren x y) (h : Ren w x) β ((h βΚ³ g) βΚ³ f) β‘ (h βΚ³ (g βΚ³ f)) βΚ³-assoc f g stop = refl βΚ³-assoc f g (drop h) = ap drop (βΚ³-assoc f g h) βΚ³-assoc f stop (keep h) = refl βΚ³-assoc f (drop g) (keep h) = ap drop (βΚ³-assoc f g h) βΚ³-assoc stop (keep g) (keep h) = refl βΚ³-assoc (drop f) (keep g) (keep h) = ap drop (βΚ³-assoc f g h) βΚ³-assoc (keep f) (keep g) (keep h) = ap keep (βΚ³-assoc f g h) ren-β¦β§βΏ : (Ο : Ren Ξ Ξ) (v : Var Ξ Ο) β β¦ ren-var Ο v β§βΏ β‘ β¦ v β§βΏ `β β¦ Ο β§Κ³ ren-β¦β§β : (Ο : Ren Ξ Ξ) (t : Ne Ξ Ο) β β¦ ren-ne Ο t β§β β‘ β¦ t β§β `β β¦ Ο β§Κ³ ren-β¦β§β : (Ο : Ren Ξ Ξ) (t : Nf Ξ Ο) β β¦ ren-nf Ο t β§β β‘ β¦ t β§β `β β¦ Ο β§Κ³ ren-β¦β§βΏ stop v = Syn.intror refl ren-β¦β§βΏ (drop Ο) v = Syn.pushl (ren-β¦β§βΏ Ο v) ren-β¦β§βΏ (keep Ο) stop = sym (Syn.Οβββ¨β©) -- sym (Syn.Οβββ¨β© β Syn.idl _) ren-β¦β§βΏ (keep Ο) (pop v) = Syn.pushl (ren-β¦β§βΏ Ο v) β sym (Syn.pullr Syn.Οβββ¨β©) ren-β¦β§β Ο (var x) = ren-β¦β§βΏ Ο x ren-β¦β§β Ο (app f x) = apβ _`β_ refl (apβ _`,_ (ren-β¦β§β Ο f) (ren-β¦β§β Ο x) β sym (Syn.β¨β©β _)) β Syn.pulll refl ren-β¦β§β Ο (fstβ t) = Syn.pushr (ren-β¦β§β Ο t) ren-β¦β§β Ο (sndβ t) = Syn.pushr (ren-β¦β§β Ο t) ren-β¦β§β Ο (hom x a) = Syn.pushr (ren-β¦β§β Ο a) ren-β¦β§β Ο (lam t) = ap `Ζ (ren-β¦β§β (keep Ο) t) β sym (Cartesian-closed.unique Free-closed _ (apβ _`β_ refl remβ β Syn.pulll `ΖΞ² β apβ _`β_ refl (apβ _`,_ refl `idl))) where remβ : (β¦ lam t β§β `β β¦ Ο β§Κ³) Syn.ββ `id β‘ (β¦ lam t β§β Syn.ββ `id) `β β¦ Ο β§Κ³ Syn.ββ `id remβ = Bifunctor.firstβfirst Syn.Γ-functor ren-β¦β§β Ο (pair a b) = apβ _`,_ (ren-β¦β§β Ο a) (ren-β¦β§β Ο b) β sym (Syn.β¨β©β _) ren-β¦β§β Ο (ne x) = ren-β¦β§β Ο x ren-β¦β§β Ο unit = `!-Ξ· _ ren-β¦β§Κ³ : β {Ξ Ξ Ξ} (f : Ren Ξ Ξ) (g : Ren Ξ Ξ) β β¦ f βΚ³ g β§Κ³ β‘ β¦ g β§Κ³ `β β¦ f β§Κ³ ren-β¦β§Κ³ stop g = sym `idr ren-β¦β§Κ³ (drop f) g = Syn.pushl (ren-β¦β§Κ³ f g) ren-β¦β§Κ³ (keep f) stop = sym `idl ren-β¦β§Κ³ (keep f) (drop g) = Syn.pushl (ren-β¦β§Κ³ f g) β sym (Syn.pullr `ΟβΞ²) ren-β¦β§Κ³ (keep f) (keep g) = sym (Syn.β¨β©-unique (Syn.pulll `ΟβΞ² β Syn.pullr `ΟβΞ² β Syn.pulll (sym (ren-β¦β§Κ³ f g))) (Syn.pulll `ΟβΞ² β `ΟβΞ²)) ren-var-βΚ³ : β {Ξ Ξ Ξ} (Ο : Ren Ξ Ξ) (Ο : Ren Ξ Ξ) (x : Var Ξ Ο) β ren-var (Ο βΚ³ Ο) x β‘ ren-var Ο (ren-var Ο x) ren-var-βΚ³ Ο stop x = ap (Ξ» e β ren-var e x) (βΚ³-idr Ο) ren-var-βΚ³ stop (drop Ο) x = refl ren-var-βΚ³ (drop Ο) (drop Ο) x = ap pop (ren-var-βΚ³ Ο (drop Ο) x) ren-var-βΚ³ (keep Ο) (drop Ο) x = ap pop (ren-var-βΚ³ Ο Ο x) ren-var-βΚ³ stop (keep Ο) x = refl ren-var-βΚ³ (drop Ο) (keep Ο) x = ap pop (ren-var-βΚ³ Ο (keep Ο) x) ren-var-βΚ³ (keep Ο) (keep Ο) stop = refl ren-var-βΚ³ (keep Ο) (keep Ο) (pop x) = ap pop (ren-var-βΚ³ Ο Ο x) ren-nf-βΚ³ : β {Ξ Ξ Ξ} (Ο : Ren Ξ Ξ) (Ο : Ren Ξ Ξ) (x : Nf Ξ Ο) β ren-nf (Ο βΚ³ Ο) x β‘ ren-nf Ο (ren-nf Ο x) ren-ne-βΚ³ : β {Ξ Ξ Ξ} (Ο : Ren Ξ Ξ) (Ο : Ren Ξ Ξ) (x : Ne Ξ Ο) β ren-ne (Ο βΚ³ Ο) x β‘ ren-ne Ο (ren-ne Ο x) ren-nf-βΚ³ Ο Ο (lam x) = ap lam (ren-nf-βΚ³ (keep Ο) (keep Ο) x) ren-nf-βΚ³ Ο Ο (pair a b) = apβ pair (ren-nf-βΚ³ Ο Ο a) (ren-nf-βΚ³ Ο Ο b) ren-nf-βΚ³ Ο Ο unit = refl ren-nf-βΚ³ Ο Ο (ne x) = ap ne (ren-ne-βΚ³ Ο Ο x) ren-ne-βΚ³ Ο Ο (var x) = ap var (ren-var-βΚ³ Ο Ο x) ren-ne-βΚ³ Ο Ο (app f x) = apβ app (ren-ne-βΚ³ Ο Ο f) (ren-nf-βΚ³ Ο Ο x) ren-ne-βΚ³ Ο Ο (fstβ x) = ap fstβ (ren-ne-βΚ³ Ο Ο x) ren-ne-βΚ³ Ο Ο (sndβ x) = ap sndβ (ren-ne-βΚ³ Ο Ο x) ren-ne-βΚ³ Ο Ο (hom n x) = ap (hom n) (ren-nf-βΚ³ Ο Ο x) data Keep : Cx β Cx β Type β where stop : Keep Ξ Ξ keep : Keep Ξ Ξ β Keep (Ξ , Ο) (Ξ , Ο) keepβren : Keep Ξ Ξ β Ren Ξ Ξ keepβren stop = stop keepβren (keep x) = keep (keepβren x) keepβctx : Keep Ξ Ξ β Ξ β‘ Ξ keepβctx stop = refl keepβctx (keep x) = apβ Cx._,_ (keepβctx x) refl ren-var-stop : (Ο : Keep Ξ Ξ) (x : Var Ξ Ο) β PathP (Ξ» i β Var (keepβctx Ο (~ i)) Ο) (ren-var (keepβren Ο) x) x ren-var-stop stop x = refl ren-var-stop (keep Ο) stop i = stop ren-var-stop (keep Ο) (pop x) i = pop (ren-var-stop Ο x i) ren-nf-stop : (Ο : Keep Ξ Ξ) (x : Nf Ξ Ο) β ren-nf (keepβren Ο) x β‘ x ren-ne-stop : (Ο : Keep Ξ Ξ) (x : Ne Ξ Ο) β ren-ne (keepβren Ο) x β‘ x ren-nf-stop Ο (lam x) = ap lam (ren-nf-stop (keep Ο) x) ren-nf-stop Ο (pair a b) = apβ pair (ren-nf-stop Ο a) (ren-nf-stop Ο b) ren-nf-stop Ο unit = refl ren-nf-stop Ο (ne x) = ap ne (ren-ne-stop Ο x) ren-ne-stop {Ο = Ο} Ο (var x) = ap var ( from-pathpβ» (ren-var-stop Ο x) ββ ap (Ξ» e β subst (Ξ» x β Var x Ο) e x) {x = keepβctx Ο} {y = refl} prop! ββ transport-refl _ ) ren-ne-stop Ο (app f x) = apβ app (ren-ne-stop Ο f) (ren-nf-stop Ο x) ren-ne-stop Ο (fstβ x) = ap fstβ (ren-ne-stop Ο x) ren-ne-stop Ο (sndβ x) = ap sndβ (ren-ne-stop Ο x) ren-ne-stop Ο (hom x n) = ap (hom x) (ren-nf-stop Ο n)
Finally, one billion copattern matches make all of this nonsense into actual categorical objects.
Rens : Precategory β β Rens .Precategory.Ob = Cx Rens .Precategory.Hom = Ren Rens .Precategory.Hom-set X Y = hlevel 2 Rens .Precategory.id = stop Rens .Precategory._β_ f g = g βΚ³ f Rens .Precategory.idr f = refl Rens .Precategory.idl f = βΚ³-idr f Rens .Precategory.assoc f g h = βΚ³-assoc f g h Sem : Type _ Sem = β PSh β Rens β RenβͺCtx : Functor Rens Free-ccc RenβͺCtx .Fβ = β¦_β§αΆ RenβͺCtx .Fβ = β¦_β§Κ³ RenβͺCtx .F-id = refl RenβͺCtx .F-β f g = ren-β¦β§Κ³ g f Tm : Functor Free-ccc (PSh β Rens) Tm = Nerve RenβͺCtx
open Pl β Rens open Pe Rens private module RenβͺCtx = Functor RenβͺCtx module Sem = Cartesian-category {C = PSh β Rens} PSh-cartesian module Tm = Functor Tm
Nfs : Ty β Sem Nfs Ο .Fβ Ξ = el! (Nf Ξ Ο) Nfs Ο .Fβ Ο = ren-nf Ο Nfs Ο .F-id = ext (ren-nf-stop stop) Nfs Ο .F-β Ο Ο = ext (ren-nf-βΚ³ Ο Ο) rnf : Nfs Ο => Tm.β Ο rnf .Ξ· Ξ Ο = β¦ Ο β§β rnf .is-natural x y f = ext (Ξ» s β ren-β¦β§β f s) Nes : Ty β Sem Nes Ο .Fβ Ξ = el! (Ne Ξ Ο) Nes Ο .Fβ Ο = ren-ne Ο Nes Ο .F-id = ext (ren-ne-stop stop) Nes Ο .F-β Ο Ο = ext (ren-ne-βΚ³ Ο Ο) rne : Nes Ο => Tm.β Ο rne .Ξ· Ξ Ο = β¦ Ο β§β rne .is-natural x y f = ext (Ξ» s β ren-β¦β§β f s)
Back from the case-bash trenches, the nerve
along the embedding
is a functor into presheaves over renamings which we write
and being a composite of Cartesian functors,
is also Cartesian. It fails to be Cartesian closed, though, so
we can not appeal to initiality in the same way. Moreover, just applying
the initiality trick again wouldnβt bring our Nf
into the picture,
either. Even worse, thatβs not how we stated the universal property
of
!
open Cartesian-functor using (pres-products ; pres-terminal) Tm-cartesian : Cartesian-functor Tm Free-cartesian PSh-cartesian Tm-cartesian .pres-products a b = Sem.make-invertible (NT (elim! (Ξ» a p q β p `, q)) Ξ» x y f β ext Ξ» p q β sym (Syn.β¨β©β _)) (ext (Ξ» i a b β `ΟβΞ² ,β `ΟβΞ²)) (ext (Ξ» i x β sym `ΟΞ·)) Tm-cartesian .pres-terminal x .centre = NT (Ξ» _ _ β `!) (Ξ» x y f β ext Ξ» a β `!-Ξ· _) Tm-cartesian .pres-terminal x .paths a = ext Ξ» i x β `!-Ξ· _
However, there is an off-the-shelf solution we can reach for: since is properly Cartesian closed (it has pullbacks), the Artin gluing is a Cartesian closed category over the syntax, as required by the universal property.
open Cat.Displayed.Instances.Gluing PSh-cartesian Free-cartesian Tm-cartesian
Surprisingly though, due to our definition of having base terms with arbitrary simple types as their domain, weβre not quite done putting together the induction. We would like to define the model of in to have the base types interpreted by normal forms (equivalently neutrals), but we have to know ahead of time how to turn our interpretation of the other simple types into neutrals.
Normalisation algebrasπ
To actually get normal forms out the other side, we will equip the
objects of
over simple types
with a structure we refer to as a normalisation
algebra. Recalling that an object in
pairs a presheaf
with a natural transformation
a normalisation algebra structure consists of further natural
transformations reifies
from
and reflects
from
5
record Nfa {Ο : Ty} (P : Gl Κ» Ο) : Type β where field reifies : P .dom => Nfs Ο reflects : Nes Ο => P .dom
β¦_β§β : β {Ξ} β P .dom Κ» Ξ β Mor β¦ Ξ β§αΆ Ο β¦_β§β {Ξ} x = P .map .Ξ· Ξ x reify : β {Ξ} β P .dom Κ» Ξ β Nf Ξ Ο reify = reifies .Ξ· _ reflect : β {Ξ} β Ne Ξ Ο β P .dom Κ» Ξ reflect = reflects .Ξ· _ field
These are required to make the following triangles commute.
comβ : {Ξ : Cx} (n : Ne Ξ Ο) β β¦ reflect n β§β β‘ β¦ n β§β comβ : {Ξ : Cx} (x : P .dom Κ» Ξ) β β¦ x β§β β‘ β¦ reify x β§β
reifyβ : β {Ξ Ξ} {Ο : Ren Ξ Ξ} {x : P .dom Κ» Ξ} β reify (P .dom βͺ Ο β« x) β‘ ren-nf Ο (reify x) reifyβ {Ξ} {Ξ} {Ο} {x} = reifies .is-natural Ξ Ξ Ο $β x reflectβ : β {Ξ Ξ} {Ο : Ren Ξ Ξ} {x : Ne Ξ Ο} β reflect (ren-ne Ο x) β‘ P .dom βͺ Ο β« (reflect x) reflectβ {Ξ} {Ξ} {Ο} {x} = reflects .is-natural Ξ Ξ Ο $β x GlTm-closed = Gl-closed PSh-closed Free-closed PSh-pullbacks open Cartesian-closed-over Gl Gl-cartesian {Free-closed} GlTm-closed using ([_,_]') open Nfa
We start by building a normalisation algebra on the presheaf of
normals, which we take as the model of base types in
This is only slightly worse than trivial, because building the
reflect
mapβ embedding neutrals into normalsβ is not literally the identity
function, but an inductive constructor instead.
Gl-base : (n : Node) β Gl Κ» (` n) Gl-base x = cut (rnf {` x}) base-nfa : β {x} β Nfa (Gl-base x) base-nfa .reifies = idnt base-nfa .reflects = record where Ξ· Ξ x = ne x is-natural Ξ Ξ Ο = ext Ξ» a β refl base-nfa .comβ x = refl base-nfa .comβ x = refl
Pairsπ
prod-nfa : β {Ο Ο x y} β Nfa {Ο} x β Nfa {Ο} y β Nfa (x ΓGl y) prod-nfa xnf ynf = record where module x = Nfa xnf module y = Nfa ynf
Next, we tackle products in
Assume we already have normalisation algebras on
and
We can reify a pair into the pair
normal form, reifying
each component in turn, and this pairing preserves naturality.
reifies = record { Ξ· = Ξ» Ξ (a , b) β pair (x.reify a) (y.reify b) ; is-natural = Ξ» Ξ Ξ Ο β ext (Ξ» a b β apβ pair x.reifyβ y.reifyβ) }
Conversely, we reflect a neutral into a pair by reflecting each
projection, first wrapping them in the constructors fstβ
and sndβ
to get something in
the right type. Again, these constructions preserve naturality.
reflects = Sem.β¨ NT (Ξ» Ξ x β x.reflect (fstβ x)) (Ξ» x y f β ext Ξ» a β x.reflectβ) , NT (Ξ» Ξ x β y.reflect (sndβ x)) (Ξ» x y f β ext Ξ» a β y.reflectβ) β©
Finally, we must commute those triangles. One is a straightforward calculation and the other is a trivial invocation of the corresponding triangle for the normalisation algebras we assumed.
comβ x = x.β¦ x.reflect (fstβ x) β§β `, y.β¦ y.reflect (sndβ x) β§β β‘β¨ apβ _`,_ (x.comβ _) (y.comβ _) β©β‘ `Οβ `β β¦ x β§β `, `Οβ `β β¦ x β§β β‘Λβ¨ Syn.β¨β©β _ β©β‘Λ (`Οβ `, `Οβ) `β β¦ x β§β β‘β¨ Syn.eliml (apβ _`,_ (sym `idr) (sym `idr) β sym `ΟΞ·) β©β‘ β¦ x β§β β comβ (a , b) = apβ _`,_ (x.comβ _) (y.comβ _)
Functionsπ
arrow-nfa : β {Ο Ο x y} β Nfa {Ο} x β Nfa {Ο} y β Nfa [ x , y ]' arrow-nfa {x = x} {y = y} xnf ynf = arr where module x = Nfa xnf module y = Nfa ynf
Next come exponential objects in which are trickier but still possible in full generality. We will once again assume that we have already built normalisation algebras for the domain and codomain We start with the implementation of reification.
Recall that the exponentials in are given by a certain pullback of and so that (at context they are given by a pair of an expression and a natural transformation with components saying that we can get a semantic value in from a renaming expressing as an extension of and a semantic value in the domain At this point, we do not yet know how to normalise the expression to obtain a normal form, so our hope lies with the natural transformation
We know that a normal form in
must be of the form
for a unique
so that we may reduce to finding a suitable
and semantic value
and, given that we can reflect
semantic values
into
we can use the neutral
To summarize, the definition of the presheaf exponential over renaming
gives an evaluation function that is stable under (in particular)
weakening. We can thus reify a natural transformation by applying it to
a fresh variable, reifying the result, and abstracting over
that variable, getting a normal form in the right context.
arr : Nfa [ x , y ]' arr .reifies .Ξ· Ξ (_ , f , p) = lam $ y.reify $ f .Ξ· _ (drop stop , x.reflect (var stop))
Reflection takes much less explanation. Given a neutral we can directly take as the first component of the glued exponential, since that is the operation we are defining. To implement the evaluation natural transformation, we see that it suffices to, given an extended context through a renaming and a semantic value produce a neutral since that reflects into a semantic value
To this end, we can rename our neutral function
to obtain
and the app
constructor says we
can apply neutral functions to normal arguments, so we obtain
A simple calculation shows that this βevaluationβ map is natural, and
that it is a definable operation built from
so we are done with the construction.
arr .reflects .Ξ· Ξ x .fst = β¦ x β§β arr .reflects .Ξ· Ξ x .snd .fst = record where Ξ· Ξ (Ο , s) = y.reflect (app (ren-ne Ο x) (x.reify s)) is-natural Ξ Ξ Ο = ext Ξ» Ο s β ap y.reflect (apβ Ne.app (ren-ne-βΚ³ Ο Ο x) x.reifyβ) β y.reflectβ arr .reflects .Ξ· Ξ x .snd .snd = ext Ξ» Ξ Ο s β sym $ y.β¦ y.reflect (app (ren-ne Ο x) (x.reify s)) β§β β‘β¨ y.comβ _ β©β‘ `ev `β (β¦ ren-ne Ο x β§β `, β¦ x.reify s β§β) β‘β¨ apβ (Ξ» a b β `ev `β (a `, b)) (ren-β¦β§β Ο x) (sym (x.comβ _)) β©β‘ `ev `β (β¦ x β§β `β β¦ Ο β§Κ³ `, x.β¦ s β§β) β
The two triangles commute by a short calculationβ the coherence
involving reflect
is definitional,
while the one involving reify
uses the pullback
condition, the βdefinabilityβ of the natural transformation, to reduce
it to something we can do substitution algebra on.
arr .comβ f = refl arr .comβ (Ο , f , Ξ±) = sym $ `Ζ β¦ y.reify (f .Ξ· _ (drop stop , x.reflect (var stop))) β§β β‘β¨ ap `Ζ (sym (y.comβ _) β sym (unext Ξ± _ _ _)) β©β‘ `Ζ (`ev `β (Ο `β `id `β `Οβ `, x.β¦ x.reflect (var stop) β§β)) β‘β¨ ap `Ζ (apβ (Ξ» a b β `ev `β (a `, b)) (ap (Ο `β_) `idl) (x.comβ _ β sym `idl)) β©β‘ `Ζ (`ev `β (Ο `β `Οβ `, `id `β `Οβ)) β‘β¨ sym `ΖΞ· β©β‘ Ο β
Strictly speaking, we must still show that the reification and reflection functions we defined above are natural. Since these are all defined in terms of other natural operations, the verification is straightforward, and so we omit it.
arr .reifies .is-natural Ξ Ξ Ο = ext Ξ» x y p β ap Nf.lam (ap y.reify (ap (Ξ» e β y .Ξ· _ e) (ap drop (sym (βΚ³-idr Ο)) ,β x.reflectβ) β (y .is-natural (Ξ , _) (Ξ , _) (keep Ο) Β·β (drop stop , _))) β y.reifyβ) arr .reflects .is-natural Ξ Ξ Ο = ext Ξ» n β Ξ£-pathp (ren-β¦β§β Ο n) $ Ξ£-prop-pathp! (ext Ξ» Ξ Ο s β ap y.reflect (apβ app (sym (ren-ne-βΚ³ Ο Ο n)) refl))
Normalisation by evaluationπ
Weβre finally ready to construct a section of First, we build a normalisation algebra on the denotation of every simple type, by a straightforward recursive argument using the βmethodsβ implemented aboveβ the case for the unit type is too simple to get a name.
normalisation : β Ο β Nfa {Ο} (Ty-nf Ο) normalisation (` x) = base-nfa normalisation (Ο `Γ Ο) = prod-nfa (normalisation Ο) (normalisation Ο) normalisation (Ο `β Ο) = arrow-nfa (normalisation Ο) (normalisation Ο) normalisation `β€ = record { reifies = NT (Ξ» Ξ _ β unit) (Ξ» Ξ Ξ Ο β refl) ; reflects = Sem.! ; comβ = Ξ» _ β `!-Ξ· _ ; comβ = Ξ» _ β refl }
This lets us model the base terms in
which is possible because (by construction) every base term
induces a natural transformation
which is componentwise the constructor hom
, and weβve constructed
natural transformations
from the interpretation of a simple type into normals, namely reifies
.
private terms : β {x : Ty} {y : Node} (e : Edge x y) β Gl.Hom[ (` e) ] (Ty-nf x) (Gl-base y) terms {x = x} {y = y} e .map = NT (Ξ» Ξ x β ne (hom e x)) (Ξ» x y f β refl) βnt Nfa.reifies (normalisation x) terms {x = x} {y = y} e .com = ext Ξ» Ξ Ο β ap ((` e) `β_) (sym (Nfa.comβ (normalisation x) _))
We thus have a section of Gl
, which performs Normalisation
.
Normalisation : Section Gl Normalisation = Free-ccc-elim terms
Letβs see how to use this to actually normalise an element
of Mor
. First,
the section of Gl
turns
into a natural transformation
To get an element of
we can pick the context
and reflect
every variable in
to obtain a semantic version of the identity substitution; and from the
resulting element of
we can reify
a
normal form
which is exactly what we wanted! Weβre finally done
.
idsec : (Ξ : Cx) β β¦ β¦ Ξ β§αΆ β§β .dom Κ» Ξ idsecΞ² : (Ξ : Cx) β β¦ β¦ Ξ β§αΆ β§β .map .Ξ· Ξ (idsec Ξ) β‘ `id
idsec β = lift tt idsec (Ξ , x) = (β¦ β¦ Ξ β§αΆ β§β .dom βͺ drop stop β« idsec Ξ) , Nfa.reflect (normalisation x) (var stop) idsecΞ² β = `!-Ξ· _ idsecΞ² (Ξ , x) = apβ _`,_ (Ξ'.map .is-natural _ _ _ Β·β _ β apβ _`β_ (idsecΞ² Ξ) refl β Syn.cancell `idl β Syn.intror refl) (Nfa.comβ (normalisation x) (var stop) β Syn.intror refl) β sym `ΟΞ· where module Ξ' = /-Obj β¦ β¦ Ξ β§αΆ β§β
nfαΆ : β Ξ {Ο : Ty} (e : Mor β¦ Ξ β§αΆ Ο) β Ξ£[ n β Nf Ξ Ο ] e β‘ β¦ n β§β nfαΆ Ξ {Ο} e = record { fst = done ; snd = sym sq } where module Ο = Nfa (normalisation Ο) done = Ο.reify (β¦ e β§β .map .Ξ· Ξ (idsec Ξ))
To show that the denotation of this normal form is the map we started with, we can calculate with the definition of morphisms in and the two triangles for the normalisation algebras on the domain and codomain, one each.
abstract sq : β¦ done β§β β‘ e sq = β¦ done β§β β‘β¨ sym (Ο.comβ _) β©β‘ Ο.β¦ β¦ e β§β .map .Ξ· Ξ (idsec Ξ) β§β β‘β¨ unext (β¦ e β§β .com) _ _ β©β‘ e `β β¦ β¦ Ξ β§αΆ β§β .map .Ξ· Ξ (idsec Ξ) β‘β¨ Syn.elimr (idsecΞ² Ξ) β©β‘ e β
Finally, using the trivial isomorphism we can normalise arbitrary morphisms
nf : β {Ο Ο : Ty} (e : Mor Ο Ο) β Ξ£[ n β Nf (β , Ο) Ο ] e β‘ β¦ n β§β `β (`! `, `id) nf {Ο} {Ο} e = let n , p = nfαΆ (β , Ο) (e `β `Οβ) in n , Equiv.adjunctl (dom-isoβhom-equiv Free-ccc Synα΅.Ξ»β ) p
Stabilityπ
We can go one step further and show that our normalisation procedure
enjoys stability: normalising a normal form leaves it
unchanged.
stability : (n : Nf Ξ Ο) β nfαΆ Ξ β¦ n β§β .fst β‘ n
stability-ne
: (n : Ne Ξ Ο)
β β¦ β¦ n β§β β§β .map .Ξ· Ξ (idsec Ξ) β‘ Nfa.reflect (normalisation Ο) n
stability-var
: (x : Var Ξ Ο)
β β¦ β¦ x β§βΏ β§β .map .Ξ· Ξ (idsec Ξ) β‘ Nfa.reflect (normalisation Ο) (var x)
stability (lam n) = ap lam (stability n) stability (pair n n') = apβ pair (stability n) (stability n') stability unit = refl stability (ne x) = stability-ne x stability-ne (var x) = stability-var x stability-ne {Ξ = Ξ} {Ο = Ο} (app {Ο = Ο} n x) = β¦ β¦ app n x β§β β§β .map .Ξ· Ξ (idsec Ξ) β‘β¨β© ev' .map .Ξ· Ξ (β¦ β¦ n β§β β§β .map .Ξ· Ξ (idsec Ξ) , β¦ β¦ x β§β β§β .map .Ξ· Ξ (idsec Ξ)) β‘β¨ ap (Ξ» a β ev' .map .Ξ· Ξ (a , β¦ β¦ x β§β β§β .map .Ξ· Ξ (idsec Ξ))) (stability-ne n) β©β‘ ev' .map .Ξ· Ξ (ΟβΟ.reflect n , β¦ β¦ x β§β β§β .map .Ξ· Ξ (idsec Ξ)) β‘β¨β© Ο.reflect (app (ren-ne stop n) (nfαΆ Ξ β¦ x β§β .fst)) β‘β¨ ap Ο.reflect (apβ app (ren-ne-stop stop n) (stability x)) β©β‘ Ο.reflect (app n x) β where module Ο = Nfa (normalisation Ο) module ΟβΟ = Nfa (normalisation (Ο `β Ο)) open Cartesian-closed-over _ _ {Free-closed} GlTm-closed stability-ne (hom x n) = ap (ne β hom x) (stability n) stability-ne (fstβ n) = ap fst (stability-ne n) stability-ne (sndβ n) = ap snd (stability-ne n) stability-var stop = refl stability-var {Ξ = Ξ , Ο} {Ο = Ο} (pop x) = (β¦ β¦ x β§βΏ β§β .map .is-natural Ξ (Ξ , Ο) (drop stop) $β idsec Ξ) β ap (β¦ Ο β§β .dom .Fβ (drop stop)) (stability-var x) β sym (Nfa.reflectβ (normalisation Ο))
This lets us conclude with a proper equivalence between morphisms and normal forms.
nfβ : Mor β¦ Ξ β§αΆ Ο β Nf Ξ Ο nfβ = IsoβEquiv (fst β nfαΆ _ , iso β¦_β§β stability (sym β snd β nfαΆ _))
Applicationsπ
Because we went out of our way to get a universal property for the
syntax which computes nicely, we can play around with the normalisation
function, as long as all the types are (Agda) normal forms. For example,
the normal form of the identity function on pairs is the pair
of the fstβ
and sndβ
projections of the
input βvariableβ, which are both neutral. We can also test that, e.g.,
the function
6, as an eta-epansion, has the same
normal form as the identity map; and that this normal form, as we
expect, is βthe function which applies the second most-recent variable
to the most recent.β
module _ (A B : Node) where _ : nf {Ο = ` A `Γ ` A} {Ο = ` A `Γ ` A} `id .fst β‘ pair (ne (fstβ (var stop))) (ne (sndβ (var stop))) _ = refl _ : nf {Ο = ` A `β ` B} {Ο = ` A `β ` B} (`Ζ (`ev `β (`Οβ `, `Οβ))) .fst β‘ nf {Ο = ` A `β ` B} {Ο = ` A `β ` B} `id .fst _ = refl _ : nf {Ο = ` A `β ` B} {Ο = ` A `β ` B} `id .fst β‘ lam (ne (app (var (pop stop)) (ne (var stop)))) _ = refl
Since normal forms are all unquotiented, first-order data, we can
decide their equality. And since every morphism is the denotation of
some normal form, we can decide equality in Mor
, too.
instance Discrete-Mor : β β¦ _ : Discrete Node β¦ β β¦ _ : β {x y} β Discrete (Edge x y) β¦ β β {Ο Ο} β Discrete (Mor Ο Ο) Discrete-Mor = Discrete-inj (fst β nf) (Ξ» {x} {y} p β nf x .snd ββ ap (Ξ» e β β¦ e β§β `β (`! `, `id)) p ββ sym (nf y .snd)) auto
While most applications of this equality decision procedure rely on
having an actual
with concrete implementations of decidable equality on base types and
base terms, we can give some examples, both positive and
negative, which are completely independent of both the choice of
and of the actual implementations of decidable equality for
base things. For example, we know by `!-Ξ·
that all morphisms
into (a function type ending in) the unit type are identical, and indeed
even with βassumedβ decidable equality we can compute this, even if the
domains are neutral types:
module _ β¦ _ : Discrete Node β¦ β¦ _ : β {x y} β Discrete (Edge x y) β¦ where _ : β {A B : Ty} {f g} β Path (Mor A (B `β `β€)) f g _ = decide!
Moreover, if we work instead against an assumed base type, so that both the domain and codomain have normalisation algebras that Agda can fully evaluate, we can e.g.Β separate the first and second projections on product types. This is true even if the base terms are such that this base type has a single inhabitant, because we did not (and, in general, can not) equip base types with eta lawsβ so in a non-empty context, base types can have distinct neutrals.
_ : β {t : Node} β _β _ {A = Mor ((` t) `Γ (` t)) (` t)} `Οβ `Οβ _ = decide!
One downside of our categorical approach to normalisation is that we cannot directly use it to write a solver for morphisms in an arbitrary Cartesian closed category, because the collection of objects does not necessarily form a set. We define a solver in a separate module, based on the same ideas.
We also define the simply-typed -calculus in a separate module as an alternative presentation of the free CCC and show how it relates to
We will use greek letters to stand for variables of type
Ty
, and upright serif letters to stand for the base types and base terms fromTo avoid name clashes with the
Ob
andHom
fields of precategories, this formalisation refers to base types as drawn fromNode
and base terms fromEdge
.This is justified by observing that any graph generates a taking the nodes as the base types, and defining the base terms so that there is an equivalence between the sets and β©οΈ
The construction of the normalisation procedure does not depend on having decidable equality.β©οΈ
We could thus define the type of normal forms by recursion on the type, rather than by induction, but we stick with the inductive definition to make pattern matching slightly more convenient.β©οΈ
If necessary to avoid clashes with other syntax, we may write context extensions as the βnamelessβ instead of using parentheses around the wordier β©οΈ
In the formalisation we reserve the imperative forms
reify
andreflect
for the components of these transformations.β©οΈNote that in both of these examples we have to βfill outβ our examples with base types under the
`_
constructor, and not simply assumed simple types, because ending up with a nice normal form requires that Agda compute the normalisation algebras into one of the concrete cases we defined above.The normal form of the identity in is still a
lam
constructor, but its body contains many redundant reify/reflect pairs that will only cancel out when and are normal forms.β©οΈ
References
- ΔubriΔ, Djordje, Peter Dybjer, and Philip Scott. 1998. βNormalization and the Yoneda Embedding.β Mathematical. Structures in Comp. Sci. 8 (2): 153β92. https://doi.org/10.1017/S0960129597002508.