module A201606.STLC.HereditarySubstitution where
open import A201606.STLC.Syntax public
open import Data.Product using (_×_) renaming (_,_ to _∙_)
open import Function using (_∘_)
mutual
data No (Γ : Cx Ty) : Ty → Set where
lamₙ : ∀ {A B} → No (Γ , A) B → No Γ (A ⊃ B)
pairₙ : ∀ {A B} → No Γ A → No Γ B → No Γ (A ∧ B)
unitₙ : No Γ ⊤
neₙ : Ne Γ ι → No Γ ι
data Ne (Γ : Cx Ty) : Ty → Set where
spₙ : ∀ {A B} → Sp Γ (B ∙ A) → A ∈ Γ → Ne Γ B
data Sp (Γ : Cx Ty) : Ty × Ty → Set where
∅ₛ : ∀ {Z} → Sp Γ (Z ∙ Z)
appₛ : ∀ {Z A B} → Sp Γ (Z ∙ B) → No Γ A → Sp Γ (Z ∙ (A ⊃ B))
fstₛ : ∀ {Z A B} → Sp Γ (Z ∙ A) → Sp Γ (Z ∙ (A ∧ B))
sndₛ : ∀ {Z A B} → Sp Γ (Z ∙ B) → Sp Γ (Z ∙ (A ∧ B))
mutual
ren-no : ∀ {Γ Γ′} → Renᵢ Γ Γ′ → Ren No Γ Γ′
ren-no ρ (lamₙ t) = lamₙ (ren-no (wk-renᵢ ρ) t)
ren-no ρ (pairₙ t u) = pairₙ (ren-no ρ t) (ren-no ρ u)
ren-no ρ unitₙ = unitₙ
ren-no ρ (neₙ t) = neₙ (ren-ne ρ t)
ren-ne : ∀ {Γ Γ′} → Renᵢ Γ Γ′ → Ren Ne Γ Γ′
ren-ne ρ (spₙ ss i) = spₙ (ren-sp ρ ss) (ρ i)
ren-sp : ∀ {Γ Γ′} → Renᵢ Γ Γ′ → Ren Sp Γ Γ′
ren-sp ρ ∅ₛ = ∅ₛ
ren-sp ρ (appₛ ss t) = appₛ (ren-sp ρ ss) (ren-no ρ t)
ren-sp ρ (fstₛ ss) = fstₛ (ren-sp ρ ss)
ren-sp ρ (sndₛ ss) = sndₛ (ren-sp ρ ss)
wk-no : ∀ {A Γ} → Ren No Γ (Γ , A)
wk-no = ren-no pop
wk-ne : ∀ {A Γ} → Ren Ne Γ (Γ , A)
wk-ne = ren-ne pop
mutual
[_≔_]ₙ_ : ∀ {A Γ} → (i : A ∈ Γ) → No (Γ -ᵢ i) A → Sub No Γ (Γ -ᵢ i)
[ i ≔ ν ]ₙ (lamₙ t) = lamₙ ([ pop i ≔ wk-no ν ]ₙ t)
[ i ≔ ν ]ₙ (pairₙ t u) = pairₙ ([ i ≔ ν ]ₙ t) ([ i ≔ ν ]ₙ u)
[ i ≔ ν ]ₙ unitₙ = unitₙ
[ i ≔ ν ]ₙ (neₙ (spₙ ss j)) with i ≟ᵢ j
[ i ≔ ν ]ₙ (neₙ (spₙ ss .i)) | same = reduce ([ i ≔ ν ]ₛ ss) ν
[ i ≔ ν ]ₙ (neₙ (spₙ ss ._)) | diff j = neₙ (spₙ ([ i ≔ ν ]ₛ ss) j)
[_≔_]ₛ_ : ∀ {A Γ} → (i : A ∈ Γ) → No (Γ -ᵢ i) A → Sub Sp Γ (Γ -ᵢ i)
[ i ≔ ν ]ₛ ∅ₛ = ∅ₛ
[ i ≔ ν ]ₛ (appₛ ss t) = appₛ ([ i ≔ ν ]ₛ ss) ([ i ≔ ν ]ₙ t)
[ i ≔ ν ]ₛ (fstₛ ss) = fstₛ ([ i ≔ ν ]ₛ ss)
[ i ≔ ν ]ₛ (sndₛ ss) = sndₛ ([ i ≔ ν ]ₛ ss)
reduce : ∀ {A B Γ} → Sp Γ (B ∙ A) → No Γ A → No Γ B
reduce ∅ₛ t = t
reduce (appₛ ss u) (lamₙ t) = reduce ss ([ top ≔ u ]ₙ t)
reduce (fstₛ ss) (pairₙ t u) = reduce ss t
reduce (sndₛ ss) (pairₙ t u) = reduce ss u
append-appₛ : ∀ {A B C Γ} → Sp Γ ((A ⊃ B) ∙ C) → No Γ A → Sp Γ (B ∙ C)
append-appₛ ∅ₛ u = appₛ ∅ₛ u
append-appₛ (appₛ ss t) u = appₛ (append-appₛ ss u) t
append-appₛ (fstₛ ss) u = fstₛ (append-appₛ ss u)
append-appₛ (sndₛ ss) u = sndₛ (append-appₛ ss u)
append-fstₛ : ∀ {A B C Γ} → Sp Γ ((A ∧ B) ∙ C) → Sp Γ (A ∙ C)
append-fstₛ ∅ₛ = fstₛ ∅ₛ
append-fstₛ (appₛ ss t) = appₛ (append-fstₛ ss) t
append-fstₛ (fstₛ ss) = fstₛ (append-fstₛ ss)
append-fstₛ (sndₛ ss) = sndₛ (append-fstₛ ss)
append-sndₛ : ∀ {A B C Γ} → Sp Γ ((A ∧ B) ∙ C) → Sp Γ (B ∙ C)
append-sndₛ ∅ₛ = sndₛ ∅ₛ
append-sndₛ (appₛ ss t) = appₛ (append-sndₛ ss) t
append-sndₛ (fstₛ ss) = fstₛ (append-sndₛ ss)
append-sndₛ (sndₛ ss) = sndₛ (append-sndₛ ss)
varₙ : ∀ {A Γ} → A ∈ Γ → Ne Γ A
varₙ i = spₙ ∅ₛ i
appₙ : ∀ {A B Γ} → Ne Γ (A ⊃ B) → No Γ A → Ne Γ B
appₙ (spₙ ss t) u = spₙ (append-appₛ ss u) t
fstₙ : ∀ {A B Γ} → Ne Γ (A ∧ B) → Ne Γ A
fstₙ (spₙ ss t) = spₙ (append-fstₛ ss) t
sndₙ : ∀ {A B Γ} → Ne Γ (A ∧ B) → Ne Γ B
sndₙ (spₙ ss t) = spₙ (append-sndₛ ss) t
expand : ∀ {A Γ} → Ne Γ A → No Γ A
expand {ι} t = neₙ t
expand {A ⊃ B} t = lamₙ (expand (appₙ (wk-ne t) (expand (varₙ top))))
expand {A ∧ B} t = pairₙ (expand (fstₙ t)) (expand (sndₙ t))
expand {⊤} t = unitₙ
tm⇒no : ∀ {A Γ} → Tm A Γ → No A Γ
tm⇒no (var i) = expand (varₙ i)
tm⇒no (lam t) = lamₙ (tm⇒no t)
tm⇒no (app t u) = reduce (appₛ ∅ₛ (tm⇒no u)) (tm⇒no t)
tm⇒no (pair t u) = pairₙ (tm⇒no t) (tm⇒no u)
tm⇒no (fst t) = reduce (fstₛ ∅ₛ) (tm⇒no t)
tm⇒no (snd t) = reduce (sndₛ ∅ₛ) (tm⇒no t)
tm⇒no unit = unitₙ
mutual
no⇒tm : ∀ {A Γ} → No Γ A → Tm Γ A
no⇒tm (lamₙ t) = lam (no⇒tm t)
no⇒tm (pairₙ t u) = pair (no⇒tm t) (no⇒tm u)
no⇒tm unitₙ = unit
no⇒tm (neₙ t) = ne⇒tm t
ne⇒tm : ∀ {A Γ} → Ne Γ A → Tm Γ A
ne⇒tm (spₙ ss i) = sp⇒tm ss (var i)
sp⇒tm : ∀ {A B Γ} → Sp Γ (B ∙ A) → Tm Γ A → Tm Γ B
sp⇒tm ∅ₛ u = u
sp⇒tm (appₛ ss t) u = sp⇒tm ss (app u (no⇒tm t))
sp⇒tm (fstₛ ss) u = sp⇒tm ss (fst u)
sp⇒tm (sndₛ ss) u = sp⇒tm ss (snd u)
norm : ∀ {A Γ} → Tm A Γ → Tm A Γ
norm = no⇒tm ∘ tm⇒no