module Type.BetaNBE.RenamingSubstitution where
open import Relation.Binary.PropositionalEquality using (_≡_;refl;sym;trans;cong;cong₂)
open Relation.Binary.PropositionalEquality.≡-Reasoning
open import Function using (_∘_)
open import Utils using (*;♯;_⇒_)
open import Type using (Ctx⋆;∅;_,⋆_;_⊢⋆_;_∋⋆_;Z;S)
open _⊢⋆_
open import Type.Equality using (_≡β_;≡2β)
open _≡β_
open import Type.RenamingSubstitution
using (Ren;ren;ext;ren-comp;sub;sub-id;sub-comp;sub-cong;exts;sub-ren;weaken;sub-∅)
open import Type.BetaNormal using (_⊢Nf⋆_;_⊢Ne⋆_;renNf;embNf;weakenNf;ren-embNf)
open _⊢Nf⋆_
open _⊢Ne⋆_
open import Type.BetaNormal.Equality using (renNf-comp)
open import Type.BetaNBE using (reify;reflect;Env;eval;nf;renVal;idEnv;_,,⋆_;fresh;exte)
open import Type.BetaNBE.Soundness using (soundness)
open import Type.BetaNBE.Completeness
using (EnvCR;CR;fund;ren-reify;idext;idCR;reifyCR;renCR;transCR;reflectCR;renVal-eval;renVal-reflect;symCR;ren-eval;sub-eval;completeness)
open import Type.BetaNBE.Stability using (stability)
Renaming is defined in the file Type.BetaNormal as it used in the NBE algorithm.
reify ∘ reflect preserves the neutral term
reify-reflect : ∀{K Φ}(n : Φ ⊢Ne⋆ K) → reify (reflect n) ≡ ne n
reify-reflect {*} n = refl
reify-reflect {♯} n = refl
reify-reflect {K ⇒ J} n = refl
eval is closed under propositional equality for terms
evalCRSubst : ∀{Φ Ψ K}{η η' : Env Φ Ψ}
→ EnvCR η η'
→ {t t' : Φ ⊢⋆ K}
→ t ≡ t'
→ CR K (eval t η) (eval t' η')
evalCRSubst p {t = t} q = fund p (≡2β q)
ren-nf : ∀{ϕ ψ K}(σ : Ren ϕ ψ)(A : ϕ ⊢⋆ K) →
renNf σ (nf A) ≡ nf (ren σ A)
ren-nf σ A = trans
(ren-reify (idext idCR A) σ)
(reifyCR
(transCR
(renVal-eval A idCR σ)
(transCR
(idext (renVal-reflect σ ∘ `) A)
(symCR (ren-eval A idCR σ)) )))
ren-nf-μ : ∀ {Φ Ψ}{K}
→ (ρ⋆ : Ren Φ Ψ)
→ (A : Φ ⊢Nf⋆ (K ⇒ *) ⇒ K ⇒ *)
→ (B : Φ ⊢Nf⋆ K)
→ renNf ρ⋆
(nf (embNf A · ƛ (μ (embNf (weakenNf A)) (` Z)) · embNf B))
≡
nf
(embNf (renNf ρ⋆ A) · ƛ (μ (embNf (weakenNf (renNf ρ⋆ A))) (` Z)) ·
embNf (renNf ρ⋆ B))
ren-nf-μ ρ⋆ A B = trans
(ren-nf ρ⋆ (embNf A · ƛ (μ (embNf (weakenNf A)) (` Z)) · embNf B))
(trans
(cong₂
(λ X Y → nf (X · ƛ (μ (ren (ext ρ⋆) (embNf (weakenNf A))) (` Z)) · Y))
(sym (ren-embNf ρ⋆ A))
(sym (ren-embNf ρ⋆ B)))
(trans
(cong
(λ X → nf (embNf (renNf ρ⋆ A) · ƛ (μ (ren (ext ρ⋆) X) (` Z)) · embNf (renNf ρ⋆ B)))
(ren-embNf S A))
(cong
(λ X → nf (embNf (renNf ρ⋆ A) · ƛ (μ X (` Z)) · embNf (renNf ρ⋆ B)))
(trans
(sym (ren-comp (embNf A)))
(trans (sym (ren-embNf (S ∘ ρ⋆) A)) (cong embNf (renNf-comp A)))))))
SubNf : Ctx⋆ → Ctx⋆ → Set
SubNf φ Ψ = ∀ {J} → φ ∋⋆ J → Ψ ⊢Nf⋆ J
Substitution for normal forms:
subNf : ∀ {Φ Ψ}
→ SubNf Φ Ψ
-------------------------
→ (∀ {J} → Φ ⊢Nf⋆ J → Ψ ⊢Nf⋆ J)
subNf ρ n = nf (sub (embNf ∘ ρ) (embNf n))
First monad law for subNf
subNf-id : ∀ {Φ J}
→ (n : Φ ⊢Nf⋆ J)
→ subNf (ne ∘ `) n ≡ n
subNf-id n = trans
(reifyCR (fund idCR (≡2β (sub-id (embNf n)))))
(stability n)
This version of the first monad law might be η compatible as it doesn’t rely on sub-id
subNf-id' : ∀ {Φ J}
→ (n : Φ ⊢Nf⋆ J)
→ subNf (nf ∘ `) n ≡ n
subNf-id' n = trans
(reifyCR
(transCR
(sub-eval (embNf n) idCR (embNf ∘ nf ∘ `))
(idext
(λ α → fund idCR (≡2β (cong embNf (stability (ne (` α))))))
(embNf n))))
(stability n)
Second monad law for subNf This is often holds definitionally for substitution (e.g. sub) but not here.
subNf-∋ : ∀ {Φ Ψ J}
→ (ρ : SubNf Φ Ψ)
→ (α : Φ ∋⋆ J)
→ subNf ρ (ne (` α)) ≡ ρ α
subNf-∋ ρ α = stability (ρ α)
Two lemmas that aim to remove a superfluous additional normalisation via stability
subNf-nf : ∀ {Φ Ψ}
→ (σ : ∀ {J} → Φ ∋⋆ J → Ψ ⊢Nf⋆ J)
→ ∀ {J}
→ (t : Φ ⊢⋆ J)
-------------------------------------------
→ nf (sub (embNf ∘ σ) t) ≡ subNf σ (nf t)
subNf-nf σ t = trans
(reifyCR (sub-eval t idCR (embNf ∘ σ)))
(trans
(sym
(reifyCR (fund (λ x → idext idCR (embNf (σ x))) (sym≡β (soundness t)))))
(sym (reifyCR (sub-eval (embNf (nf t)) idCR (embNf ∘ σ)))))
Third Monad Law for subNf
subNf-comp : ∀{Φ Ψ Θ}
(g : SubNf Φ Ψ)
(f : SubNf Ψ Θ)
→ ∀{J}(A : Φ ⊢Nf⋆ J)
-----------------------------------------------
→ subNf (subNf f ∘ g) A ≡ subNf f (subNf g A)
subNf-comp g f A = trans
(trans
(trans
(reifyCR
(sub-eval
(embNf A)
idCR
(embNf ∘ nf ∘ sub (embNf ∘ f) ∘ embNf ∘ g)))
(trans (reifyCR
(idext
(λ x → fund
idCR
(sym≡β (soundness (sub (embNf ∘ f) (embNf (g x))))))
(embNf A)))
(sym
(reifyCR
(sub-eval
(embNf A)
idCR
(sub (embNf ∘ f) ∘ embNf ∘ g))))))
(completeness (≡2β (sub-comp (embNf A)))))
(subNf-nf f (sub (embNf ∘ g) (embNf A)))
extending a normal substitution
extsNf : ∀ {Φ Ψ}
→ SubNf Φ Ψ
-------------------------------
→ ∀ {K} → SubNf (Φ ,⋆ K) (Ψ ,⋆ K)
extsNf σ Z = ne (` Z)
extsNf σ (S α) = weakenNf (σ α)
cons for normal substitutions
subNf-cons : ∀{Φ Ψ}
→ (∀{K} → Φ ∋⋆ K → Ψ ⊢Nf⋆ K)
→ ∀{J}(A : Ψ ⊢Nf⋆ J)
→ (∀{K} → Φ ,⋆ J ∋⋆ K → Ψ ⊢Nf⋆ K)
subNf-cons σ A Z = A
subNf-cons σ A (S x) = σ x
Substitution of one variable
_[_]Nf : ∀ {Φ J K}
→ Φ ,⋆ K ⊢Nf⋆ J
→ Φ ⊢Nf⋆ K
------
→ Φ ⊢Nf⋆ J
A [ B ]Nf = subNf (subNf-cons (ne ∘ `) B) A
Congruence lemma for sub
subNf-cong : ∀ {Φ Ψ}
→ {f g : ∀{K} → Φ ∋⋆ K → Ψ ⊢Nf⋆ K}
→ (∀ {J}(x : Φ ∋⋆ J) → f x ≡ g x)
→ ∀{K}(A : Φ ⊢Nf⋆ K)
-------------------------------
→ subNf f A ≡ subNf g A
subNf-cong p A =
reifyCR (fund idCR (≡2β (sub-cong (cong embNf ∘ p ) (embNf A))))
subNf-cong' : ∀ {Φ Ψ}
→ (f : ∀{K} → Φ ∋⋆ K → Ψ ⊢Nf⋆ K)
→ ∀{K}{A A' : Φ ⊢Nf⋆ K}
→ A ≡ A'
-------------------------------
→ subNf f A ≡ subNf f A'
subNf-cong' f p = cong (subNf f) p
Pushing renaming through normal substitution
renNf-subNf : ∀{Φ Ψ Θ}
→ (g : SubNf Φ Ψ)
→ (f : Ren Ψ Θ)
→ ∀{J}(A : Φ ⊢Nf⋆ J)
-----------------------------------------------------
→ subNf (renNf f ∘ g) A ≡ renNf f (subNf g A)
renNf-subNf g f A = trans
(reifyCR
(transCR
(transCR
(sub-eval (embNf A) idCR (embNf ∘ renNf f ∘ g))
(transCR
(idext
(λ α → transCR
(evalCRSubst idCR (ren-embNf f (g α)))
(transCR
(ren-eval (embNf (g α)) idCR f)
(idext (symCR ∘ renVal-reflect f ∘ `) (embNf (g α)))))
(embNf A))
(symCR (sub-eval (embNf A) (renCR f ∘ idCR) (embNf ∘ g)))))
(symCR (renVal-eval (sub (embNf ∘ g) (embNf A)) idCR f))))
(sym (ren-reify (idext idCR (sub (embNf ∘ g) (embNf A))) f))
Pushing a substitution through a renaming
subNf-renNf : ∀{Φ Ψ Θ}
→ (g : Ren Φ Ψ)
→ (f : SubNf Ψ Θ)
→ ∀{J}(A : Φ ⊢Nf⋆ J)
--------------------------------------
→ subNf (f ∘ g) A ≡ subNf f (renNf g A)
subNf-renNf g f A = reifyCR
(transCR
(sub-eval (embNf A) idCR (embNf ∘ f ∘ g))
(transCR
(transCR
(symCR (ren-eval (embNf A) (λ α → idext idCR (embNf (f α))) g))
(symCR
(evalCRSubst (λ α → idext idCR (embNf (f α))) (ren-embNf g A))))
(symCR (sub-eval (embNf (renNf g A)) idCR (embNf ∘ f)))))
Pushing renaming through a one variable normal substitution
ren[]Nf : ∀ {Φ Θ J K}
→ (ρ : Ren Φ Θ)
→ (t : Φ ,⋆ K ⊢Nf⋆ J)
→ (u : Φ ⊢Nf⋆ K )
--------------------------------------------------------------
→ renNf ρ (t [ u ]Nf) ≡ (renNf (ext ρ) t [ renNf ρ u ]Nf)
ren[]Nf ρ t u = trans
(sym (renNf-subNf (subNf-cons (ne ∘ `) u) ρ t))
(trans
(subNf-cong
{f = renNf ρ ∘ subNf-cons (ne ∘ `) u}
{g = subNf-cons (ne ∘ `) (renNf ρ u) ∘ ext ρ}
(λ { Z → refl ; (S α) → refl})
t)
(subNf-renNf (ext ρ)(subNf-cons (ne ∘ `) (renNf ρ u)) t))
Pushing a normal substitution through a one place normal substitution
sub[]Nf : ∀{Φ Ψ K J}
→ (ρ : ∀{K} → Φ ∋⋆ K → Ψ ⊢Nf⋆ K)
→ (A : Φ ⊢Nf⋆ K)
→ (B : Φ ,⋆ K ⊢Nf⋆ J)
--------------------------------------------------------------
→ subNf ρ (B [ A ]Nf) ≡ (subNf (extsNf ρ) B [ subNf ρ A ]Nf)
sub[]Nf ρ A B = trans
(sym (subNf-comp (subNf-cons (ne ∘ `) A) ρ B))
(trans
(subNf-cong
{f = subNf ρ ∘ subNf-cons (ne ∘ `) A}
{g = subNf (subNf-cons (ne ∘ `) (subNf ρ A)) ∘ extsNf ρ}
(λ { Z → sym (subNf-∋ (subNf-cons (ne ∘ `) (subNf ρ A)) Z)
; (S α) → trans
(trans (subNf-∋ ρ α) (sym (subNf-id (ρ α))))
(subNf-renNf
S
(subNf-cons (ne ∘ `) (subNf ρ A))
(ρ α))})
B)
(subNf-comp (extsNf ρ) (subNf-cons (ne ∘ `) (subNf ρ A)) B))
Extending a normal environment and then embedding is the same as embedding and then extending.
subNf-lemma : ∀{Φ Ψ K J}
(ρ : ∀{K} → Φ ∋⋆ K → Ψ ⊢Nf⋆ K)
→ (t : Φ ,⋆ K ⊢⋆ J)
→ sub (exts (embNf ∘ ρ)) t ≡ sub (embNf ∘ extsNf ρ) t
subNf-lemma ρ t =
sub-cong (λ { Z → refl ; (S x) → sym (ren-embNf S (ρ x))}) t
Repair a mismatch between two different ways of extending an environment
subNf-lemma' : ∀{Φ K J}
→ (B : Φ ,⋆ K ⊢⋆ J)
→ nf B ≡ reify (eval B ((renVal S ∘ idEnv _) ,,⋆ fresh))
subNf-lemma' B = reifyCR
(idext (λ { Z → reflectCR refl
; (S x) → symCR (renVal-reflect S (` x))}) B)
combining the above lemmas
note: there are several mismatches here, one due to two different ways of extending a normal substitution and another due to two different ways of extending an environment
sub[]Nf' : ∀{Φ Ψ K J}
→ (ρ : ∀{K} → Φ ∋⋆ K → Ψ ⊢Nf⋆ K)
→ (A : Φ ⊢Nf⋆ K)
→ (B : Φ ,⋆ K ⊢Nf⋆ J)
→ subNf ρ (B [ A ]Nf)
≡
((reify (eval (sub (exts (embNf ∘ ρ)) (embNf B))
((renVal S ∘ idEnv _) ,,⋆ fresh)))
[ subNf ρ A ]Nf)
sub[]Nf' ρ A B =
trans (sub[]Nf ρ A B)
(subNf-cong' (subNf-cons (ne ∘ `) (subNf ρ A))
{A = subNf (extsNf ρ) B}
{A' =
reify
(eval (sub (exts (embNf ∘ ρ)) (embNf B))
((renVal S ∘ idEnv _) ,,⋆ fresh))}
(trans (sym (completeness (≡2β (subNf-lemma ρ (embNf B)))))
(subNf-lemma' (sub (exts (embNf ∘ ρ)) (embNf B)))))
weakenNf-renNf : ∀ {Φ Ψ}
→ (ρ⋆ : Ren Φ Ψ)
→ ∀{K}
→ (A : Φ ⊢Nf⋆ *)
→ weakenNf (renNf ρ⋆ A) ≡ renNf (ext ρ⋆ {K = K}) (weakenNf A)
weakenNf-renNf ρ⋆ A = trans (sym (renNf-comp _)) (renNf-comp _)
weakenNf-subNf : ∀ {Φ Ψ}
→ (σ⋆ : SubNf Φ Ψ)
→ ∀{K}
→ (A : Φ ⊢Nf⋆ *)
→ weakenNf (subNf σ⋆ A) ≡ subNf (extsNf σ⋆ {K = K}) (weakenNf A)
weakenNf-subNf σ⋆ A = trans
(sym (renNf-subNf σ⋆ S A))
(subNf-renNf S (extsNf σ⋆) A)
weakenNf[] : ∀ {Φ K}(B : Φ ⊢Nf⋆ K)
→ (A : Φ ⊢Nf⋆ *)
→ A ≡ (weakenNf A [ B ]Nf)
weakenNf[] B A = trans
(trans (sym (stability A))
(evalCRSubst idCR (sym (sub-id (embNf A)))))
(subNf-renNf S (subNf-cons (ne ∘ `) B) A)
sub-nf-Π : ∀ {Φ Ψ}
→ (σ⋆ : SubNf Φ Ψ)
→ ∀{K}
→ (B : Φ ,⋆ K ⊢Nf⋆ *)
→ subNf (extsNf σ⋆) B
≡
eval (sub (exts (embNf ∘ σ⋆)) (embNf B)) (exte (idEnv Ψ))
sub-nf-Π σ⋆ B = trans
(evalCRSubst idCR (sym (subNf-lemma σ⋆ (embNf B))))
(subNf-lemma' (sub (exts (embNf ∘ σ⋆)) (embNf B)))
sub-nf-μ : ∀ {Φ Ψ}{K}
→ (σ⋆ : SubNf Φ Ψ)
→ (A : Φ ⊢Nf⋆ (K ⇒ *) ⇒ K ⇒ *)
→ (B : Φ ⊢Nf⋆ K)
→ subNf σ⋆ (nf (embNf A · ƛ (μ (embNf (weakenNf A)) (` Z)) · embNf B))
≡
nf
(embNf (subNf σ⋆ A) ·
ƛ (μ (embNf (weakenNf (subNf σ⋆ A))) (` Z))
· embNf (subNf σ⋆ B))
sub-nf-μ σ⋆ A B = trans
(sym (subNf-nf σ⋆ (embNf A · ƛ (μ (embNf (weakenNf A)) (` Z)) · embNf B)))
(completeness
{s = sub (embNf ∘ σ⋆) (embNf A) · ƛ (μ (sub (exts (embNf ∘ σ⋆)) (embNf (weakenNf A))) (` Z)) · sub (embNf ∘ σ⋆) (embNf B)}
{(embNf (subNf σ⋆ A) · ƛ (μ (embNf (weakenNf (subNf σ⋆ A))) (` Z)) · embNf (subNf σ⋆ B))}
(·≡β
(·≡β
(soundness (sub (embNf ∘ σ⋆) (embNf A)))
(ƛ≡β (μ≡β
(trans≡β
(trans≡β
(≡2β (cong (sub (exts (embNf ∘ σ⋆))) (ren-embNf S A)))
(trans≡β
(≡2β (sym (sub-ren (embNf A))))
(trans≡β
(soundness (sub (weaken ∘ embNf ∘ σ⋆) (embNf A)))
(≡2β
(cong embNf {nf (sub (weaken ∘ embNf ∘ σ⋆) (embNf A))}{subNf (renNf S ∘ σ⋆) A}
(cong nf (sub-cong (sym ∘ ren-embNf S ∘ σ⋆) (embNf A))))))))
(≡2β (cong embNf (renNf-subNf σ⋆ S A))))
(refl≡β (` Z)))))
(soundness (sub (embNf ∘ σ⋆) (embNf B)))))
subNf-cons-[]Nf : ∀{Φ K Ψ'}{σ : SubNf Ψ' Φ}{A : Φ ⊢Nf⋆ K}(X : Ψ' ,⋆ K ⊢Nf⋆ *) →
subNf (subNf-cons σ A) X
≡
reify (eval (sub (exts (embNf ∘ σ)) (embNf X)) (exte (idEnv Φ))) [ A ]Nf
subNf-cons-[]Nf {σ = σ}{A} X = trans
(trans (subNf-cong {f = subNf-cons σ A}{g = subNf (subNf-cons (ne ∘ `) A) ∘ extsNf σ} (λ {Z → sym (stability A) ; (S α) → trans (trans (sym (stability (σ α))) (cong nf (sym (sub-id (embNf (σ α)))))) (subNf-renNf S (subNf-cons (ne ∘ `) A) (σ α)) }) X)
(subNf-comp (extsNf σ)
(subNf-cons (ne ∘ `) A)
X))
(cong (_[ A ]Nf)
(sub-nf-Π σ X))
-- A version of subNf that is definitionally the identity on the empty context
subNf∅ : ∀{Φ K} → ∅ ⊢Nf⋆ K → Φ ⊢Nf⋆ K
subNf∅ {∅} t = t
subNf∅ {Φ ,⋆ x} t = subNf (λ()) t
-- But this is equivalent to the normal subNf
subNf∅≡subNf : ∀{Φ K} → {A : ∅ ⊢Nf⋆ K} → subNf∅ {Φ} A ≡ subNf (λ()) A
subNf∅≡subNf {∅} {_} {A} = begin
A
≡⟨ sym (stability A) ⟩
nf (embNf A)
≡⟨ cong nf (sym (sub-∅ (embNf A) (embNf ∘ λ()))) ⟩
nf (sub (embNf ∘ λ()) (embNf A))
≡⟨ refl ⟩
subNf (λ ()) A
∎
subNf∅≡subNf {Φ ,⋆ x} = refl
subNf∅-renNf : ∀{Φ Ψ K} (ρ : Ren Φ Ψ) (A : ∅ ⊢Nf⋆ K) → renNf ρ (subNf∅ A) ≡ subNf∅ A
subNf∅-renNf ρ A = begin
renNf ρ (subNf∅ A)
≡⟨ cong (renNf ρ) subNf∅≡subNf ⟩
renNf ρ (subNf (λ ()) A)
≡⟨ sym (renNf-subNf (λ()) ρ A) ⟩
subNf (renNf ρ ∘ (λ ())) A
≡⟨ sym (subNf-cong {f = λ()} {renNf ρ ∘ λ ()} (λ ()) A) ⟩
subNf (λ ()) A
≡⟨ sym subNf∅≡subNf ⟩
subNf∅ A
∎
subNf∅-subNf : ∀{Φ Ψ K} → (σ : SubNf Φ Ψ) → (A : ∅ ⊢Nf⋆ K) → subNf σ (subNf∅ A) ≡ subNf∅ A
subNf∅-subNf σ A = begin
subNf σ (subNf∅ A)
≡⟨ cong (subNf σ) subNf∅≡subNf ⟩
subNf σ (subNf (λ ()) A)
≡⟨ sym (subNf-comp (λ()) σ A) ⟩
subNf (subNf σ ∘ (λ ())) A
≡⟨ subNf-cong {f = subNf σ ∘ (λ ())} {λ ()} (λ ()) A ⟩
subNf (λ ()) A
≡⟨ sym subNf∅≡subNf ⟩
subNf∅ A
∎