module Cat.CartesianClosed.Solver
Solver for Cartesian closed categoriesπ
{o β} {C : Precategory o β} (cart : Cartesian-category C) (cc : Cartesian-closed C cart) where open Cartesian-category cart open Cartesian-closed cc open types Ob public
We can write a solver for a Cartesian closed category β a metaprogram which identifies two morphisms when they differ only by applications of the CCC laws β by re-using the idea for our implementation of normalisation by evaluation for free Cartesian closed categories: in order to identify two morphisms in it suffices to identify their βquotedβ versions in the free CCC on which we can do automatically by normalising them.
The reason we donβt directly re-use the implementation is that the underlying graph of an arbitrary CCC does not form a -signature unless the category is strict, which is too limiting an assumption. In turn, the requirement that the objects form a set is necessary to obtain proper presheaves of normals and neutrals. Instead, this module takes a slightly βwilderβ approach, omitting a lot of unnecessary coherence. We also work with an unquotiented representation of morphisms.
First, recall the definition of simple types: they are generated from the objects of by freely adding product types, function types, and a unit type. We define contexts as lists of simple types.
data Cx : Type o where β : Cx _,_ : Cx β Ty β Cx
Using the Cartesian closed structure of we can interpret types and contexts in terms of the structural morphisms: for example, the empty context is interpreted by the terminal object.
β¦_β§α΅ : Ty β Ob β¦_β§αΆ : Cx β Ob
β¦ X `Γ Y β§α΅ = β¦ X β§α΅ ββ β¦ Y β§α΅ β¦ X `β Y β§α΅ = [ β¦ X β§α΅ , β¦ Y β§α΅ ] β¦ `β€ β§α΅ = top β¦ ` X β§α΅ = X β¦ Ξ , Ο β§αΆ = β¦ Ξ β§αΆ ββ β¦ Ο β§α΅ β¦ β β§αΆ = top
The idea is then to write a faithful representation of the way morphisms in a CCC appear in equational goals (in terms of identities, compositions, the evaluation morphism, and so on), then define a sound normalisation function for these. Note that since this is a metaprogram, our syntax for morphisms does not need to actually respect the laws of a CCC (i.e. it does not need to be a higher inductive type). Itβs just a big indexed inductive type with constructors for all the βprimitiveβ morphism formers for a terminal object, products, and exponential objects, with an additional constructor for morphisms from the base category.
data Mor : Ty β Ty β Type (o β β) where -- Generators: `_ : β {x y} β Hom β¦ x β§α΅ β¦ y β§α΅ β Mor x y -- A CCC is a category: `id : Mor Ο Ο _`β_ : Mor Ο Ο β Mor Ο Ο β Mor Ο Ο -- A CCC has a terminal object: `! : Mor Ο `β€ -- A CCC has products: `Οβ : Mor (Ο `Γ Ο) Ο `Οβ : Mor (Ο `Γ Ο) Ο _`,_ : Mor Ο Ο β Mor Ο Ο β Mor Ο (Ο `Γ Ο) -- A CCC has exponentials: `ev : Mor ((Ο `β Ο) `Γ Ο) Ο `Ζ : Mor (Ο `Γ Ο) Ο β Mor Ο (Ο `β Ο)
infixr 20 _`β_ infixr 19 _`,_ _`ββ_ infix 25 `_ pattern _`ββ_ f g = f `β `Οβ `, g `β `Οβ pattern `unlambda f = `ev `β (f `ββ `id)
We can interpret a formal morphism from to as a map in and this interpretation definitionally sends each constructor to its corresponding operation.
β¦_β§α΅ : Mor Ο Ο β Hom β¦ Ο β§α΅ β¦ Ο β§α΅ β¦ ` x β§α΅ = x β¦ `id β§α΅ = id β¦ m `β mβ β§α΅ = β¦ m β§α΅ β β¦ mβ β§α΅ β¦ `Οβ β§α΅ = Οβ β¦ `Οβ β§α΅ = Οβ β¦ m `, mβ β§α΅ = β¨ β¦ m β§α΅ , β¦ mβ β§α΅ β© β¦ `ev β§α΅ = ev β¦ `Ζ m β§α΅ = Ζ β¦ m β§α΅ β¦ `! β§α΅ = !
The bulk of this module is the implementation of normalisation by evaluation for the representation of morphisms above. We refer the reader to the same construction for free Cartesian closed categories over a for more details.
data Var : Cx β Ty β Type o where stop : Var (Ξ , Ο) Ο pop : Var Ξ Ο β Var (Ξ , Ο) Ο β¦_β§βΏ : Var Ξ Ο β Hom β¦ Ξ β§αΆ β¦ Ο β§α΅ β¦ stop β§βΏ = Οβ β¦ pop x β§βΏ = β¦ x β§βΏ β Οβ data Ren : Cx β Cx β Type (o β β) where stop : Ren Ξ Ξ drop : Ren Ξ Ξ β Ren (Ξ , Ο) Ξ keep : Ren Ξ Ξ β Ren (Ξ , Ο) (Ξ , Ο) _βΚ³_ : β {Ξ Ξ Ξ} β Ren Ξ Ξ β Ren Ξ Ξ β Ren Ξ Ξ stop βΚ³ Ο = Ο drop Ο βΚ³ Ο = drop (Ο βΚ³ Ο) keep Ο βΚ³ stop = keep Ο keep Ο βΚ³ drop Ο = drop (Ο βΚ³ Ο) keep Ο βΚ³ keep Ο = keep (Ο βΚ³ Ο) ren-var : β {Ξ Ξ Ο} β Ren Ξ Ξ β Var Ξ Ο β Var Ξ Ο 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 Ξ Ξ β Hom β¦ Ξ β§αΆ β¦ Ξ β§αΆ β¦ stop β§Κ³ = id β¦ drop r β§Κ³ = β¦ r β§Κ³ β Οβ β¦ keep r β§Κ³ = β¦ r β§Κ³ ββ id data Nf : Cx β Ty β Type (o β β) data Ne : Cx β Ty β Type (o β β) data Sub (Ξ : Cx) : Cx β Type (o β β) data Nf where lam : Nf (Ξ , Ο) Ο β Nf Ξ (Ο `β Ο) pair : Nf Ξ Ο β Nf Ξ Ο β Nf Ξ (Ο `Γ Ο) unit : Nf Ξ `β€ ne : β {x} β Ne Ξ (` x) β Nf Ξ (` x) data Ne where var : Var Ξ Ο β Ne Ξ Ο app : Ne Ξ (Ο `β Ο) β Nf Ξ Ο β Ne Ξ Ο fstβ : Ne Ξ (Ο `Γ Ο) β Ne Ξ Ο sndβ : Ne Ξ (Ο `Γ Ο) β Ne Ξ Ο hom : β {Ξ a} β Hom β¦ Ξ β§αΆ a β Sub Ξ Ξ β Ne Ξ (` a) data Sub Ξ where β : Sub Ξ β _,_ : Sub Ξ Ξ β Nf Ξ Ο β Sub Ξ (Ξ , Ο) ren-ne : β {Ξ Ξ Ο} β Ren Ξ Ξ β Ne Ξ Ο β Ne Ξ Ο ren-nf : β {Ξ Ξ Ο} β Ren Ξ Ξ β Nf Ξ Ο β Nf Ξ Ο ren-sub : β {Ξ Ξ Ξ} β Ren Ξ Ξ β Sub Ξ Ξ β Sub Ξ Ξ ren-ne Ο (hom h a) = hom h (ren-sub Ο a) 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-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 ren-sub Ο β = β ren-sub Ο (Ο , x) = ren-sub Ο Ο , ren-nf Ο x β¦_β§β : Nf Ξ Ο β Hom β¦ Ξ β§αΆ β¦ Ο β§α΅ β¦_β§β : Ne Ξ Ο β Hom β¦ Ξ β§αΆ β¦ Ο β§α΅ β¦_β§α΅£ : Sub Ξ Ξ β Hom β¦ Ξ β§αΆ β¦ Ξ β§αΆ β¦ 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 h a β§β = h β β¦ a β§α΅£ β¦ β β§α΅£ = ! β¦ Ο , n β§α΅£ = β¨ β¦ Ο β§α΅£ , β¦ n β§β β© β¦β§-βΚ³ : (Ο : Ren Ξ Ξ) (Ο : Ren Ξ Ξ) β β¦ Ο βΚ³ Ο β§Κ³ β‘ β¦ Ο β§Κ³ β β¦ Ο β§Κ³ 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-β¦β§α΅£ : (Ο : Ren Ξ Ξ) (Ο : Sub Ξ Ξ) β β¦ ren-sub Ο Ο β§α΅£ β‘ β¦ Ο β§α΅£ β β¦ Ο β§Κ³ β¦β§-βΚ³ stop Ο = intror refl β¦β§-βΚ³ (drop Ο) Ο = pushl (β¦β§-βΚ³ Ο Ο) β¦β§-βΚ³ (keep Ο) stop = introl refl β¦β§-βΚ³ (keep Ο) (drop Ο) = pushl (β¦β§-βΚ³ Ο Ο) β sym (pullr Οβββ¨β©) β¦β§-βΚ³ (keep Ο) (keep Ο) = sym $ β¨β©-unique (pulll Οβββ¨β© β pullr Οβββ¨β© β pulll (sym (β¦β§-βΚ³ Ο Ο))) (pulll Οβββ¨β© β pullr Οβββ¨β© β idl _) ren-β¦β§βΏ stop v = intror refl ren-β¦β§βΏ (drop Ο) v = pushl (ren-β¦β§βΏ Ο v) ren-β¦β§βΏ (keep Ο) stop = sym (Οβββ¨β© β idl _) ren-β¦β§βΏ (keep Ο) (pop v) = pushl (ren-β¦β§βΏ Ο v) β sym (pullr Οβββ¨β©) ren-β¦β§β Ο (var x) = ren-β¦β§βΏ Ο x ren-β¦β§β Ο (app f x) = apβ _β_ refl (apβ β¨_,_β© (ren-β¦β§β Ο f) (ren-β¦β§β Ο x) β sym (β¨β©β _)) β pulll refl ren-β¦β§β Ο (fstβ t) = pushr (ren-β¦β§β Ο t) ren-β¦β§β Ο (sndβ t) = pushr (ren-β¦β§β Ο t) ren-β¦β§β Ο (hom x a) = pushr (ren-β¦β§α΅£ Ο a) ren-β¦β§β Ο (lam t) = ap Ζ (ren-β¦β§β (keep Ο) t) β sym (unique _ (apβ _β_ refl remβ β pulll (commutes β¦ t β§β))) where remβ : (β¦ lam t β§β β β¦ Ο β§Κ³) ββ id β‘ (β¦ lam t β§β ββ id) β β¦ Ο β§Κ³ ββ id remβ = Bifunctor.firstβfirst Γ-functor ren-β¦β§β Ο (pair a b) = apβ β¨_,_β© (ren-β¦β§β Ο a) (ren-β¦β§β Ο b) β sym (β¨β©β _) ren-β¦β§β Ο (ne x) = ren-β¦β§β Ο x ren-β¦β§β Ο unit = !-unique _ ren-β¦β§α΅£ Ο β = !-unique _ ren-β¦β§α΅£ Ο (Ο , n) = apβ β¨_,_β© (ren-β¦β§α΅£ Ο Ο) (ren-β¦β§β Ο n) β sym (β¨β©β _) Tyα΅ : (Ο : Ty) (Ξ : Cx) β Hom β¦ Ξ β§αΆ β¦ Ο β§α΅ β Type (o β β) Tyα΅ (Ο `Γ Ο) Ξ h = Tyα΅ Ο Ξ (Οβ β h) Γ Tyα΅ Ο Ξ (Οβ β h) Tyα΅ `β€ Ξ h = Lift _ β€ Tyα΅ (Ο `β Ο) Ξ h = β {Ξ} (Ο : Ren Ξ Ξ) {a} β Tyα΅ Ο Ξ a β Tyα΅ Ο Ξ (ev β β¨ h β β¦ Ο β§Κ³ , a β©) Tyα΅ (` x) Ξ h = Ξ£ (Ne Ξ (` x)) Ξ» n β β¦ n β§β β‘ h data Subα΅ : β Ξ Ξ β Hom β¦ Ξ β§αΆ β¦ Ξ β§αΆ β Type (o β β) where β : β {i} β Subα΅ β Ξ i _,_ : β {h} β Subα΅ Ξ Ξ (Οβ β h) β Tyα΅ Ο Ξ (Οβ β h) β Subα΅ (Ξ , Ο) Ξ h tyα΅β¨_β© : β {Ο Ξ h h'} β h β‘ h' β Tyα΅ Ο Ξ h β Tyα΅ Ο Ξ h' tyα΅β¨_β© {Ο `Γ Ο} p (a , b) = tyα΅β¨ ap (Οβ β_) p β©tyα΅ a , tyα΅β¨ ap (Οβ β_) p β©tyα΅ b tyα΅β¨_β© {Ο `β Ο} p Ξ½ Ο x = tyα΅β¨ ap (Ξ» e β ev β β¨ e β β¦ Ο β§Κ³ , _ β©) p β©tyα΅ (Ξ½ Ο x) tyα΅β¨_β© {` x} p (n , q) .fst = n tyα΅β¨_β© {` x} p (n , q) .snd = q β p tyα΅β¨_β© {`β€} p (lift tt) = lift tt subα΅β¨_β© : β {Ξ Ξ h h'} β h β‘ h' β Subα΅ Ξ Ξ h β Subα΅ Ξ Ξ h' subα΅β¨_β© p β = β subα΅β¨_β© p (r , x) = subα΅β¨ ap (Οβ β_) p β©subα΅ r , tyα΅β¨ ap (Οβ β_) p β©tyα΅ x ren-tyα΅ : β {Ξ Ξ Ο m} (Ο : Ren Ξ Ξ) β Tyα΅ Ο Ξ m β Tyα΅ Ο Ξ (m β β¦ Ο β§Κ³) ren-subα΅ : β {Ξ Ξ Ξ m} (Ο : Ren Ξ Ξ) β Subα΅ Ξ Ξ m β Subα΅ Ξ Ξ (m β β¦ Ο β§Κ³) ren-tyα΅ {Ο = Ο `Γ Ο} r (a , b) = tyα΅β¨ sym (assoc _ _ _) β©tyα΅ (ren-tyα΅ r a) , tyα΅β¨ sym (assoc _ _ _) β©tyα΅ (ren-tyα΅ r b) ren-tyα΅ {Ο = Ο `β Ο} r t {Ξ} Ο {Ξ±} a = tyα΅β¨ ap (Ξ» e β ev β β¨ e , Ξ± β©) (pushr (β¦β§-βΚ³ Ο r)) β©tyα΅ (t (Ο βΚ³ r) a) ren-tyα΅ {Ο = ` x} r (f , p) = ren-ne r f , ren-β¦β§β r f β apβ _β_ p refl ren-tyα΅ {Ο = `β€} r (lift tt) = lift tt ren-subα΅ r β = β ren-subα΅ r (c , x) = subα΅β¨ sym (assoc _ _ _) β©subα΅ (ren-subα΅ r c) , tyα΅β¨ sym (assoc _ _ _) β©tyα΅ (ren-tyα΅ r x) reifyα΅ : β {h} β Tyα΅ Ο Ξ h β Nf Ξ Ο reflectα΅ : (n : Ne Ξ Ο) β Tyα΅ Ο Ξ β¦ n β§β reifyα΅-correct : β {h} (v : Tyα΅ Ο Ξ h) β β¦ reifyα΅ v β§β β‘ h reifyα΅ {Ο = Ο `Γ s} (a , b) = pair (reifyα΅ a) (reifyα΅ b) reifyα΅ {Ο = Ο `β s} f = lam (reifyα΅ (f (drop stop) (reflectα΅ (var stop)))) reifyα΅ {Ο = ` x} d = ne (d .fst) reifyα΅ {Ο = `β€} d = unit reflectα΅ {Ο = Ο `Γ Ο} n = reflectα΅ (fstβ n) , reflectα΅ (sndβ n) reflectα΅ {Ο = Ο `β Ο} n Ο a = tyα΅β¨ apβ (Ξ» e f β ev β β¨ e , f β©) (ren-β¦β§β Ο n) (reifyα΅-correct a) β©tyα΅ (reflectα΅ (app (ren-ne Ο n) (reifyα΅ a))) reflectα΅ {Ο = ` x} n = n , refl reflectα΅ {Ο = `β€} _ = lift tt reifyα΅-correct {Ο = Ο `Γ Ο} (a , b) = sym $ β¨β©-unique (sym (reifyα΅-correct a)) (sym (reifyα΅-correct b)) reifyα΅-correct {Ο = Ο `β Ο} {h = h} Ξ½ = Ζ β¦ reifyα΅ (Ξ½ (drop stop) (reflectα΅ (var stop))) β§β β‘β¨ ap Ζ (reifyα΅-correct (Ξ½ (drop stop) (reflectα΅ (var stop)))) β©β‘ Ζ (ev β β¨ h β id β Οβ , Οβ β©) β‘β¨ apβ (Ξ» a b β Ζ (ev β β¨ a , b β©)) (pulll (elimr refl)) (introl refl) β©β‘ Ζ (unlambda h) β‘Λβ¨ unique _ refl β©β‘Λ h β reifyα΅-correct {Ο = ` x} d = d .snd reifyα΅-correct {Ο = `β€} d = !-unique _ private tickα΅ : β {x y h} (m : Hom β¦ x β§α΅ β¦ y β§α΅) β Tyα΅ x Ξ h β Tyα΅ y Ξ (m β h) tickα΅ {x = x} {y = `β€} m a = lift tt tickα΅ {x = x} {y = ` Ο} m a = hom {Ξ = β , x} (m β Οβ) (β , reifyα΅ a) , pullr Οβββ¨β© β ap (m β_) (reifyα΅-correct a) tickα΅ {y = Ο `Γ Ο} m a = tyα΅β¨ pullr refl β©tyα΅ (tickα΅ (Οβ β m) a) , tyα΅β¨ pullr refl β©tyα΅ (tickα΅ (Οβ β m) a) tickα΅ {x = x} {y = Ο `β Ο} m a Ο y = tyα΅β¨ pullr (β¨β©-unique (pulll Οβββ¨β© β extendr Οβββ¨β©) (pulll Οβββ¨β© β Οβββ¨β©)) β©tyα΅ (tickα΅ {x = x `Γ Ο} (ev β β¨ m β Οβ , Οβ β©) (tyα΅β¨ sym Οβββ¨β© β©tyα΅ (ren-tyα΅ Ο a) , tyα΅β¨ sym Οβββ¨β© β©tyα΅ y)) morα΅ : β {h} (e : Mor Ο Ο) (Ο : Tyα΅ Ο Ξ h) β Tyα΅ Ο Ξ (β¦ e β§α΅ β h) morα΅ (` x) = tickα΅ x morα΅ `id Ο = tyα΅β¨ introl refl β©tyα΅ Ο morα΅ (f `β g) Ο = tyα΅β¨ pulll refl β©tyα΅ (morα΅ f (morα΅ g Ο)) morα΅ `! Ο = lift tt morα΅ `Οβ Ο = Ο .fst morα΅ `Οβ Ο = Ο .snd morα΅ (e `, f) Ο = record { fst = tyα΅β¨ sym (pulll Οβββ¨β©) β©tyα΅ (morα΅ e Ο) ; snd = tyα΅β¨ sym (pulll Οβββ¨β©) β©tyα΅ (morα΅ f Ο) } morα΅ `ev (f , x) = tyα΅β¨ ap (ev β_) (sym (β¨β©-unique (intror refl) refl)) β©tyα΅ (f stop x) morα΅ {h = h} (`Ζ e) t r {h'} a = tyα΅β¨ sym p β©tyα΅ (morα΅ e ( tyα΅β¨ sym Οβββ¨β© β©tyα΅ (ren-tyα΅ r t) , tyα΅β¨ sym Οβββ¨β© β©tyα΅ a )) where p = ev β β¨ ((Ζ β¦ e β§α΅) β h) β β¦ r β§Κ³ , h' β© β‘β¨ ap (ev β_) (sym (β¨β©-unique (pulll Οβββ¨β© β pullr Οβββ¨β© β pulll refl) (pulll Οβββ¨β© β pullr Οβββ¨β© β idl _))) β©β‘ ev β (Ζ β¦ e β§α΅ ββ id) β β¨ h β β¦ r β§Κ³ , h' β© β‘β¨ pulll (commutes _) β©β‘ β¦ e β§α΅ β β¨ h β β¦ r β§Κ³ , h' β© β
Putting the NbE pieces together, we get a normalisation function
together with a proof of soundness, which allows us to write a solve
function.
mor-nf : Mor Ο Ο β Nf (β , Ο) Ο mor-nf m = reifyα΅ (morα΅ m (reflectα΅ (var stop))) mor-nf-sound : (m : Mor Ο Ο) β β¦ m β§α΅ β‘ β¦ mor-nf m β§β β β¨ ! , id β© mor-nf-sound m = sym $ β¦ mor-nf m β§β β β¨ ! , id β© β‘β¨ pushl (reifyα΅-correct (morα΅ m (reflectα΅ (var stop)))) β©β‘ β¦ m β§α΅ β Οβ β β¨ ! , id β© β‘β¨ elimr Οβββ¨β© β©β‘ β¦ m β§α΅ β abstract solve : (m n : Mor Ο Ο) β mor-nf m β‘ mor-nf n β β¦ m β§α΅ β‘ β¦ n β§α΅ solve m n p = β¦ m β§α΅ β‘β¨ mor-nf-sound m β©β‘ β¦ mor-nf m β§β β β¨ ! , id β© β‘β¨ apβ _β_ (ap β¦_β§β p) refl β©β‘ β¦ mor-nf n β§β β β¨ ! , id β© β‘β¨ sym (mor-nf-sound n) β©β‘ β¦ n β§α΅ β
private module _ {W X Y Z} (f : Hom X Y) (g : Hom X Z) (h : Hom W X) where `W `X `Y `Z : Ty `W = ` W ; `X = ` X ; `Y = ` Y ; `Z = ` Z `f : Mor `X `Y `f = ` f `g : Mor `X `Z `g = ` g `h : Mor `W `X `h = ` h
We can then test that the solver subsumes the solver for products, handles for the terminal object, and can handle both and when it comes to the Cartesian closed structure.
test-ΟΞ· : (pair : Hom X (Y ββ Z)) β pair β‘ β¨ Οβ β pair , Οβ β pair β© test-ΟΞ· p = solve {Ο = `X} {`Y `Γ `Z} `p (`Οβ `β `p `, `Οβ `β `p) refl where `p = ` p test-ΟΞ²β : Οβ β β¨ f , g β© β‘ f test-ΟΞ²β = solve (`Οβ `β (`f `, `g)) `f refl test-ΟΞ²β : Οβ β β¨ f , g β© β‘ g test-ΟΞ²β = solve (`Οβ `β (`f `, `g)) `g refl test-β¨β©β : β¨ f β h , g β h β© β‘ β¨ f , g β© β h test-β¨β©β = solve (`f `β `h `, `g `β `h) ((`f `, `g) `β `h) refl test-ΖΞ² : (f : Hom X [ Y , Z ]) β f β‘ Ζ (unlambda f) test-ΖΞ² fn = solve `fn (`Ζ (`unlambda `fn)) refl where `fn : Mor `X (`Y `β `Z) ; `fn = ` fn test-Ζh : (o : Hom (X ββ Y) Z) β o β‘ unlambda (Ζ o) test-Ζh o = solve `o (`unlambda (`Ζ `o)) refl where `o : Mor (`X `Γ `Y) `Z ; `o = ` o test-!Ξ· : (f g : Hom X top) β f β‘ g test-!Ξ· f g = solve {Ο = `X} {Ο = `β€} (` f) (` g) refl