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
private variable
: Cx
Γ Δ Θ : Ty τ σ ρ
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:
: Mor σ σ
`id _`∘_ : Mor σ ρ → Mor τ σ → Mor τ ρ
-- A CCC has a terminal object:
: Mor τ `⊤
`!
-- A CCC has products:
: Mor (τ `× σ) τ
`π₁ : Mor (τ `× σ) σ
`π₂ _`,_ : Mor τ σ → Mor τ ρ → Mor τ (σ `× ρ)
-- A CCC has exponentials:
: Mor ((τ `⇒ σ) `× τ) σ
`ev : 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
: Var (Γ , τ) τ
stop : Var Γ τ → Var (Γ , σ) τ
pop
_⟧ⁿ : Var Γ τ → Hom ⟦ Γ ⟧ᶜ ⟦ τ ⟧ᵗ
⟦= π₂
⟦ stop ⟧ⁿ = ⟦ x ⟧ⁿ ∘ π₁
⟦ pop x ⟧ⁿ
data Ren : Cx → Cx → Type (o ⊔ ℓ) where
: Ren Γ Γ
stop : Ren Γ Δ → Ren (Γ , τ) Δ
drop : Ren Γ Δ → Ren (Γ , τ) (Δ , τ)
keep
_∘ʳ_ : ∀ {Γ Δ Θ} → Ren Γ Δ → Ren Δ Θ → Ren Γ Θ
= ρ
stop ∘ʳ ρ = drop (σ ∘ʳ ρ)
drop σ ∘ʳ ρ = keep σ
keep σ ∘ʳ stop = drop (σ ∘ʳ ρ)
keep σ ∘ʳ drop ρ = keep (σ ∘ʳ ρ)
keep σ ∘ʳ keep ρ
: ∀ {Γ Δ τ} → Ren Γ Δ → Var Δ τ → Var Γ τ
ren-var = v
ren-var stop v (drop σ) v = pop (ren-var σ v)
ren-var (keep σ) stop = stop
ren-var (keep σ) (pop v) = pop (ren-var σ v)
ren-var
_⟧ʳ : Ren Γ Δ → Hom ⟦ Γ ⟧ᶜ ⟦ Δ ⟧ᶜ
⟦= id
⟦ stop ⟧ʳ = ⟦ r ⟧ʳ ∘ π₁
⟦ drop r ⟧ʳ = ⟦ r ⟧ʳ ⊗₁ id
⟦ keep r ⟧ʳ
data Nf : Cx → Ty → Type (o ⊔ ℓ)
data Ne : Cx → Ty → Type (o ⊔ ℓ)
data Sub (Γ : Cx) : Cx → Type (o ⊔ ℓ)
data Nf where
: Nf (Γ , τ) σ → Nf Γ (τ `⇒ σ)
lam : Nf Γ τ → Nf Γ σ → Nf Γ (τ `× σ)
pair : Nf Γ `⊤
unit : ∀ {x} → Ne Γ (` x) → Nf Γ (` x)
ne
data Ne where
: Var Γ τ → Ne Γ τ
var : Ne Γ (τ `⇒ σ) → Nf Γ τ → Ne Γ σ
app : Ne Γ (τ `× σ) → Ne Γ τ
fstₙ : Ne Γ (τ `× σ) → Ne Γ σ
sndₙ : ∀ {Δ a} → Hom ⟦ Δ ⟧ᶜ a → Sub Γ Δ → Ne Γ (` a)
hom
data Sub Γ where
: Sub Γ ∅
∅ _,_ : Sub Γ Δ → Nf Γ τ → Sub Γ (Δ , τ)
: ∀ {Γ Δ τ} → Ren Δ Γ → Ne Γ τ → Ne Δ τ
ren-ne : ∀ {Γ Δ τ} → Ren Δ Γ → Nf Γ τ → Nf Δ τ
ren-nf : ∀ {Γ Δ Θ} → Ren Δ Γ → Sub Γ Θ → Sub Δ Θ
ren-sub
(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-ne σ
(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
ren-nf σ unit
= ∅
ren-sub ρ ∅ (σ , x) = ren-sub ρ σ , ren-nf ρ x
ren-sub ρ
_⟧ₙ : Nf Γ τ → Hom ⟦ Γ ⟧ᶜ ⟦ τ ⟧ᵗ
⟦_⟧ₛ : Ne Γ τ → Hom ⟦ Γ ⟧ᶜ ⟦ τ ⟧ᵗ
⟦_⟧ᵣ : Sub Γ Δ → Hom ⟦ Γ ⟧ᶜ ⟦ Δ ⟧ᶜ
⟦
= ƛ ⟦ h ⟧ₙ
⟦ lam h ⟧ₙ = ⟨ ⟦ a ⟧ₙ , ⟦ b ⟧ₙ ⟩
⟦ pair a b ⟧ₙ = ⟦ x ⟧ₛ
⟦ ne x ⟧ₙ = !
⟦ unit ⟧ₙ
= ⟦ x ⟧ⁿ
⟦ var x ⟧ₛ = ev ∘ ⟨ ⟦ f ⟧ₛ , ⟦ x ⟧ₙ ⟩
⟦ app f x ⟧ₛ = π₁ ∘ ⟦ h ⟧ₛ
⟦ fstₙ h ⟧ₛ = π₂ ∘ ⟦ h ⟧ₛ
⟦ sndₙ h ⟧ₛ = h ∘ ⟦ a ⟧ᵣ
⟦ hom h a ⟧ₛ
= !
⟦ ∅ ⟧ᵣ = ⟨ ⟦ σ ⟧ᵣ , ⟦ n ⟧ₙ ⟩
⟦ σ , n ⟧ᵣ
: (ρ : 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 ρ σ ⟧ᵣ ≡ ⟦ σ ⟧ᵣ ∘ ⟦ ρ ⟧ʳ
ren-⟦⟧ᵣ
= intror refl
⟦⟧-∘ʳ stop σ (drop ρ) σ = pushl (⟦⟧-∘ʳ ρ σ)
⟦⟧-∘ʳ (keep ρ) stop = introl refl
⟦⟧-∘ʳ (keep ρ) (drop σ) = pushl (⟦⟧-∘ʳ ρ σ) ∙ sym (pullr π₁∘⟨⟩)
⟦⟧-∘ʳ (keep ρ) (keep σ) = sym $ ⟨⟩-unique
⟦⟧-∘ʳ (pulll π₁∘⟨⟩ ∙ pullr π₁∘⟨⟩ ∙ pulll (sym (⟦⟧-∘ʳ ρ σ)))
(pulll π₂∘⟨⟩ ∙ pullr π₂∘⟨⟩ ∙ idl _)
= intror refl
ren-⟦⟧ⁿ stop v (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
ren-⟦⟧ₛ ρ (ap₂ ⟨_,_⟩ (ren-⟦⟧ₛ ρ f) (ren-⟦⟧ₙ ρ x) ∙ sym (⟨⟩∘ _))
∙ pulll refl(fstₙ t) = pushr (ren-⟦⟧ₛ ρ t)
ren-⟦⟧ₛ ρ (sndₙ t) = pushr (ren-⟦⟧ₛ ρ t)
ren-⟦⟧ₛ ρ (hom x a) = pushr (ren-⟦⟧ᵣ ρ a)
ren-⟦⟧ₛ ρ
(lam t) =
ren-⟦⟧ₙ ρ (ren-⟦⟧ₙ (keep ρ) t)
ap ƛ (unique _ (ap₂ _∘_ refl rem₁ ∙ pulll (commutes ⟦ t ⟧ₙ)))
∙ sym where
: (⟦ lam t ⟧ₙ ∘ ⟦ ρ ⟧ʳ) ⊗₁ id ≡ (⟦ lam t ⟧ₙ ⊗₁ id) ∘ ⟦ ρ ⟧ʳ ⊗₁ id
rem₁ = Bifunctor.first∘first ×-functor
rem₁
(pair a b) = ap₂ ⟨_,_⟩ (ren-⟦⟧ₙ ρ a) (ren-⟦⟧ₙ ρ b) ∙ sym (⟨⟩∘ _)
ren-⟦⟧ₙ ρ (ne x) = ren-⟦⟧ₛ ρ x
ren-⟦⟧ₙ ρ = !-unique _
ren-⟦⟧ₙ ρ unit
= !-unique _
ren-⟦⟧ᵣ ρ ∅ (σ , n) = ap₂ ⟨_,_⟩ (ren-⟦⟧ᵣ ρ σ) (ren-⟦⟧ₙ ρ n) ∙ sym (⟨⟩∘ _)
ren-⟦⟧ᵣ ρ
: (τ : Ty) (Γ : Cx) → Hom ⟦ Γ ⟧ᶜ ⟦ τ ⟧ᵗ → Type (o ⊔ ℓ)
Tyᵖ (τ `× σ) Γ h = Tyᵖ τ Γ (π₁ ∘ h) × Tyᵖ σ Γ (π₂ ∘ h)
Tyᵖ = Lift _ ⊤
Tyᵖ `⊤ Γ h (τ `⇒ σ) Γ h =
Tyᵖ ∀ {Δ} (ρ : Ren Δ Γ) {a}
→ Tyᵖ τ Δ a
→ Tyᵖ σ Δ (ev ∘ ⟨ h ∘ ⟦ ρ ⟧ʳ , a ⟩)
(` x) Γ h = Σ (Ne Γ (` x)) λ n → ⟦ n ⟧ₛ ≡ h
Tyᵖ
data Subᵖ : ∀ Γ Δ → Hom ⟦ Δ ⟧ᶜ ⟦ Γ ⟧ᶜ → Type (o ⊔ ℓ) where
: ∀ {i} → Subᵖ ∅ Δ i
∅ _,_ : ∀ {h} → Subᵖ Γ Δ (π₁ ∘ h) → Tyᵖ σ Δ (π₂ ∘ h) → Subᵖ (Γ , σ) Δ h
_⟩ : ∀ {τ Γ h h'} → h ≡ h' → Tyᵖ τ Γ h → Tyᵖ τ Γ h'
tyᵖ⟨_⟩ {τ `× σ} p (a , b) = tyᵖ⟨ ap (π₁ ∘_) p ⟩ a , tyᵖ⟨ ap (π₂ ∘_) p ⟩ b
tyᵖ⟨_⟩ {τ `⇒ σ} p ν ρ x = tyᵖ⟨ ap (λ e → ev ∘ ⟨ e ∘ ⟦ ρ ⟧ʳ , _ ⟩) p ⟩ (ν ρ x)
tyᵖ⟨_⟩ {` x} p (n , q) .fst = n
tyᵖ⟨_⟩ {` x} p (n , q) .snd = q ∙ p
tyᵖ⟨_⟩ {`⊤} p (lift tt) = lift tt
tyᵖ⟨
_⟩ : ∀ {Γ Δ h h'} → h ≡ h' → Subᵖ Γ Δ h → Subᵖ Γ Δ h'
subᵖ⟨_⟩ p ∅ = ∅
subᵖ⟨_⟩ p (r , x) = subᵖ⟨ ap (π₁ ∘_) p ⟩ r , tyᵖ⟨ ap (π₂ ∘_) p ⟩ x
subᵖ⟨
: ∀ {Δ Γ τ m} (ρ : Ren Δ Γ) → Tyᵖ τ Γ m → Tyᵖ τ Δ (m ∘ ⟦ ρ ⟧ʳ)
ren-tyᵖ : ∀ {Δ Γ Θ m} (ρ : Ren Θ Δ) → Subᵖ Γ Δ m → Subᵖ Γ Θ (m ∘ ⟦ ρ ⟧ʳ)
ren-subᵖ
{τ = τ `× σ} r (a , b) =
ren-tyᵖ (assoc _ _ _) ⟩ (ren-tyᵖ r a)
tyᵖ⟨ sym (assoc _ _ _) ⟩ (ren-tyᵖ r b)
, tyᵖ⟨ sym {τ = τ `⇒ σ} r t {Θ} ρ {α} a =
ren-tyᵖ (λ e → ev ∘ ⟨ e , α ⟩) (pushr (⟦⟧-∘ʳ ρ r)) ⟩ (t (ρ ∘ʳ r) a)
tyᵖ⟨ ap {τ = ` x} r (f , p) = ren-ne r f , ren-⟦⟧ₛ r f ∙ ap₂ _∘_ p refl
ren-tyᵖ {τ = `⊤} r (lift tt) = lift tt
ren-tyᵖ
= ∅
ren-subᵖ r ∅ (c , x) =
ren-subᵖ r (assoc _ _ _) ⟩ (ren-subᵖ r c)
subᵖ⟨ sym (assoc _ _ _) ⟩ (ren-tyᵖ r x)
, tyᵖ⟨ sym
: ∀ {h} → Tyᵖ τ Γ h → Nf Γ τ
reifyᵖ : (n : Ne Γ τ) → Tyᵖ τ Γ ⟦ n ⟧ₛ
reflectᵖ : ∀ {h} (v : Tyᵖ τ Γ h) → ⟦ reifyᵖ v ⟧ₙ ≡ h
reifyᵖ-correct
{τ = τ `× 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
reifyᵖ
{τ = τ `× σ} n = reflectᵖ (fstₙ n) , reflectᵖ (sndₙ n)
reflectᵖ {τ = τ `⇒ σ} n ρ a = tyᵖ⟨ ap₂ (λ e f → ev ∘ ⟨ e , f ⟩) (ren-⟦⟧ₛ ρ n) (reifyᵖ-correct a) ⟩
reflectᵖ (reflectᵖ (app (ren-ne ρ n) (reifyᵖ a)))
{τ = ` x} n = n , refl
reflectᵖ {τ = `⊤} _ = lift tt
reflectᵖ
{τ = τ `× σ} (a , b) = sym $
reifyᵖ-correct (sym (reifyᵖ-correct a)) (sym (reifyᵖ-correct b))
⟨⟩-unique {τ = τ `⇒ σ} {h = h} ν =
reifyᵖ-correct (ν (drop stop) (reflectᵖ (var stop))) ⟧ₙ
ƛ ⟦ reifyᵖ (reifyᵖ-correct (ν (drop stop) (reflectᵖ (var stop)))) ⟩
≡⟨ ap ƛ (ev ∘ ⟨ h ∘ id ∘ π₁ , π₂ ⟩)
ƛ (λ a b → ƛ (ev ∘ ⟨ a , b ⟩)) (pulll (elimr refl)) (introl refl) ⟩
≡⟨ ap₂ (unlambda h)
ƛ _ refl ⟩
≡˘⟨ unique
h ∎{τ = ` x} d = d .snd
reifyᵖ-correct {τ = `⊤} d = !-unique _
reifyᵖ-correct
private
: ∀ {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 =
tickᵖ {Δ = ∅ , x} (m ∘ π₂) (∅ , reifyᵖ a) ,
hom (m ∘_) (reifyᵖ-correct a)
pullr π₂∘⟨⟩ ∙ ap
{y = τ `× σ} m a =
tickᵖ (tickᵖ (π₁ ∘ m) a)
tyᵖ⟨ pullr refl ⟩ (tickᵖ (π₂ ∘ m) a)
, tyᵖ⟨ pullr refl ⟩
{x = x} {y = τ `⇒ σ} m a ρ y =
tickᵖ (⟨⟩-unique (pulll π₁∘⟨⟩ ∙ extendr π₁∘⟨⟩) (pulll π₂∘⟨⟩ ∙ π₂∘⟨⟩)) ⟩
tyᵖ⟨ pullr (tickᵖ {x = x `× τ} (ev ∘ ⟨ m ∘ π₁ , π₂ ⟩)
(tyᵖ⟨ sym π₁∘⟨⟩ ⟩ (ren-tyᵖ ρ a) , tyᵖ⟨ sym π₂∘⟨⟩ ⟩ y))
: ∀ {h} (e : Mor τ σ) (ρ : Tyᵖ τ Γ h) → Tyᵖ σ Γ (⟦ e ⟧ᵐ ∘ h)
morᵖ (` x) = tickᵖ x
morᵖ
= tyᵖ⟨ introl refl ⟩ ρ
morᵖ `id ρ (f `∘ g) ρ = tyᵖ⟨ pulll refl ⟩ (morᵖ f (morᵖ g ρ))
morᵖ
= lift tt
morᵖ `! ρ = ρ .fst
morᵖ `π₁ ρ = ρ .snd
morᵖ `π₂ ρ (e `, f) ρ = record
morᵖ { fst = tyᵖ⟨ sym (pulll π₁∘⟨⟩) ⟩ (morᵖ e ρ)
; snd = tyᵖ⟨ sym (pulll π₂∘⟨⟩) ⟩ (morᵖ f ρ)
}
(f , x) = tyᵖ⟨ ap (ev ∘_) (sym (⟨⟩-unique (intror refl) refl)) ⟩
morᵖ `ev (f stop x)
{h = h} (`ƛ e) t r {h'} a = tyᵖ⟨ sym p ⟩ (morᵖ e
morᵖ ( tyᵖ⟨ sym π₁∘⟨⟩ ⟩ (ren-tyᵖ r t)
))
, tyᵖ⟨ sym π₂∘⟨⟩ ⟩ a where
=
p ((ƛ ⟦ e ⟧ᵐ) ∘ h) ∘ ⟦ r ⟧ʳ , h' ⟩
ev ∘ ⟨ (ev ∘_) (sym (⟨⟩-unique (pulll π₁∘⟨⟩ ∙ pullr π₁∘⟨⟩ ∙ pulll refl) (pulll π₂∘⟨⟩ ∙ pullr π₂∘⟨⟩ ∙ idl _))) ⟩
≡⟨ ap (ƛ ⟦ e ⟧ᵐ ⊗₁ id) ∘ ⟨ h ∘ ⟦ r ⟧ʳ , h' ⟩
ev ∘ (commutes _) ⟩
≡⟨ pulll
⟦ 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 = reifyᵖ (morᵖ m (reflectᵖ (var stop)))
mor-nf m
: (m : Mor τ σ) → ⟦ m ⟧ᵐ ≡ ⟦ mor-nf m ⟧ₙ ∘ ⟨ ! , id ⟩
mor-nf-sound = sym $
mor-nf-sound m (reifyᵖ-correct (morᵖ m (reflectᵖ (var stop)))) ⟩
⟦ mor-nf m ⟧ₙ ∘ ⟨ ! , id ⟩ ≡⟨ pushl
⟦ m ⟧ᵐ ∘ π₂ ∘ ⟨ ! , id ⟩ ≡⟨ elimr π₂∘⟨⟩ ⟩
⟦ m ⟧ᵐ ∎
abstract
: (m n : Mor τ σ) → mor-nf m ≡ mor-nf n → ⟦ m ⟧ᵐ ≡ ⟦ n ⟧ᵐ
solve =
solve m n p
⟦ m ⟧ᵐ ≡⟨ mor-nf-sound m ⟩_∘_ (ap ⟦_⟧ₙ p) refl ⟩
⟦ mor-nf m ⟧ₙ ∘ ⟨ ! , id ⟩ ≡⟨ ap₂ (mor-nf-sound n) ⟩
⟦ mor-nf n ⟧ₙ ∘ ⟨ ! , id ⟩ ≡⟨ sym ⟦ n ⟧ᵐ ∎
private module _ {W X Y Z} (f : Hom X Y) (g : Hom X Z) (h : Hom W X) where
: Ty
`W `X `Y `Z = ` W ; `X = ` X ; `Y = ` Y ; `Z = ` Z
`W
: Mor `X `Y
`f = ` f
`f
: Mor `X `Z
`g = ` g
`g
: Mor `W `X
`h = ` 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.
: (pair : Hom X (Y ⊗₀ Z)) → pair ≡ ⟨ π₁ ∘ pair , π₂ ∘ pair ⟩
test-πη = solve {τ = `X} {`Y `× `Z} `p (`π₁ `∘ `p `, `π₂ `∘ `p) refl
test-πη p where `p = ` p
: π₁ ∘ ⟨ 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-ƛβ = solve `fn (`ƛ (`unlambda `fn)) refl
test-ƛβ fn where `fn : Mor `X (`Y `⇒ `Z) ; `fn = ` fn
: (o : Hom (X ⊗₀ Y) Z) → o ≡ unlambda (ƛ o)
test-ƛh = solve `o (`unlambda (`ƛ `o)) refl
test-ƛh o where `o : Mor (`X `× `Y) `Z ; `o = ` o
: (f g : Hom X top) → f ≡ g
test-!η = solve {τ = `X} {σ = `⊤} (` f) (` g) refl test-!η f g