{-# OPTIONS --safe #-}
module CtxTyp.Reduction where
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (ℕ; suc; zero; _≥‴_; ≤‴-refl; ≤‴-step)
open import Function using (id; _∘_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import CtxTyp.Context
open import CtxTyp.Term
open import CtxTyp.Depth
open import CtxTyp.Substitution
variable
e e₁ e₂ e₃ e′ e₁′ e₂′ e₃′ e″ : Term n Γ A
_[_] : Γ ,[ Δ ⊢ A ^ m≥n ] ⊢ B ^ n → Γ ↾≥ m≥n ++ Δ ⊢ A ^ m → Γ ⊢ B ^ n
e₁ [ e₂ ] = subst (lift id , term e₂) e₁
data Value : Γ ⊢ A ^ n → Set where
`λ⟨_⟩_ : ∀ Δ → (e : Γ ,[ inject₁ Δ ⊢ A ^ ≤‴-refl ] ⊢ B ^ n) → Value (`λ⟨ Δ ⟩ e)
`true : Value {Γ = Γ} `true
`false : Value {Γ = Γ} `false
⟨_⟩ : (e : Γ ↾ ⊢ A ^ suc n) → Value {Γ = Γ} ⟨ e ⟩
`wrap : ∀ Δ → (e : Γ ++ inject₁ Δ ⊢ A ^ n) → (v : Value e) → Value (`wrap Δ e)
infix 4 _-→_
data _-→_ {n} {Γ} : Γ ⊢ A ^ n → Γ ⊢ A ^ n → Set where
β-λ⟨⟩· : Value e₂ → (`λ⟨ Δ ⟩ e₁) · e₂ -→ e₁ [ e₂ ]
β-if-true : `if `true `then e₂ `else e₃ -→ e₂
β-if-false : `if `false `then e₂ `else e₃ -→ e₃
β-let⟨⟩ : {e₂ : Γ ,[ Δ ⊢ A ^ ≤‴-step ≤‴-refl ] ⊢ B ^ n} → `let⟨ Δ ⟩ ⟨ e₁ ⟩ e₂ -→ e₂ [ rename (ext++ˡ (Γ ↾) (∋-inject₁⁻ ∘ ∋-↾⁻)) e₁ ]
β-letwrap : Value (`wrap Δ e₁) → `letwrap Δ (`wrap Δ e₁) e₂ -→ e₂ [ e₁ ]
ξ-·₁ : e₁ -→ e₁′ → e₁ · e₂ -→ e₁′ · e₂
ξ-·₂ : Value e₁ → e₂ -→ e₂′ → e₁ · e₂ -→ e₁ · e₂′
ξ-if₁ : e₁ -→ e₁′ → `if e₁ `then e₂ `else e₃ -→ `if e₁′ `then e₂ `else e₃
ξ-let⟨⟩₁ : e₁ -→ e₁′ → `let⟨ Δ ⟩ e₁ e₂ -→ `let⟨ Δ ⟩ e₁′ e₂
ξ-wrap : e -→ e′ → `wrap Δ e -→ `wrap Δ e′
ξ-letwrap₁ : e₁ -→ e₁′ → `letwrap Δ e₁ e₂ -→ `letwrap Δ e₁′ e₂
data Progress : Γ ⊢ A ^ n → Set where
p-step : e -→ e′ → Progress e
p-value : Value e → Progress e
progress : (e : inject₁ Γ ⊢ A ^ n) → Progress e
progress (` x `with σ) = ⊥-elim (inject₁-∌-refl x)
progress `true = p-value `true
progress `false = p-value `false
progress (`if e₁ `then e₂ `else e₃) with progress e₁
... | p-step e₁-→e₁′ = p-step (ξ-if₁ e₁-→e₁′)
... | p-value `true = p-step β-if-true
... | p-value `false = p-step β-if-false
progress (`λ⟨ Δ ⟩ e) = p-value (`λ⟨ Δ ⟩ e)
progress (e₁ · e₂) with progress e₁
... | p-step e₁-→e₁′ = p-step (ξ-·₁ e₁-→e₁′)
... | p-value ve₁@(`λ⟨ Δ ⟩ e₁′) with progress e₂
... | p-step e₂-→e₂′ = p-step (ξ-·₂ ve₁ e₂-→e₂′)
... | p-value ve₂ = p-step (β-λ⟨⟩· ve₂)
progress ⟨ e ⟩ = p-value ⟨ e ⟩
progress (`let⟨ Δ ⟩ e₁ e₂) with progress e₁
... | p-step e₁-→e₁′ = p-step (ξ-let⟨⟩₁ e₁-→e₁′)
... | p-value ⟨ e ⟩ = p-step β-let⟨⟩
progress (`wrap Δ e) with progress e
... | p-step e-→e′ = p-step (ξ-wrap e-→e′)
... | p-value ve = p-value (`wrap Δ e ve)
progress (`letwrap Δ e₁ e₂) with progress e₁
... | p-step e₁-→e₁′ = p-step (ξ-letwrap₁ e₁-→e₁′)
... | p-value v₁@(`wrap Δ e ve) = p-step (β-letwrap v₁)
infix 4 _-→*_
data _-→*_ {n} {Γ} : Γ ⊢ A ^ n → Γ ⊢ A ^ n → Set where
-→*-refl : e -→* e
-→*-step : e -→ e′ → e′ -→* e″ → e -→* e″
-→*-reflexive : e ≡ e′ → e -→* e′
-→*-reflexive refl = -→*-refl
-→*-trans : e -→* e′ → e′ -→* e″ → e -→* e″
-→*-trans -→*-refl = id
-→*-trans (-→*-step e-→e₁ e₁-→*e′) = -→*-step e-→e₁ ∘ -→*-trans e₁-→*e′
ξ-if₁* : e₁ -→* e₁′ → `if e₁ `then e₂ `else e₃ -→* `if e₁′ `then e₂ `else e₃
ξ-if₁* -→*-refl = -→*-refl
ξ-if₁* (-→*-step e₁-→e₁′ e₁′-→*e₁″) = -→*-step (ξ-if₁ e₁-→e₁′) (ξ-if₁* e₁′-→*e₁″)
ξ-·₁* : e₁ -→* e₁′ → e₁ · e₂ -→* e₁′ · e₂
ξ-·₁* -→*-refl = -→*-refl
ξ-·₁* (-→*-step e₁-→e₁′ e₁′-→*e₁″) = -→*-step (ξ-·₁ e₁-→e₁′) (ξ-·₁* e₁′-→*e₁″)
ξ-·₂* : Value e₁ → e₂ -→* e₂′ → e₁ · e₂ -→* e₁ · e₂′
ξ-·₂* ve₁ -→*-refl = -→*-refl
ξ-·₂* ve₁ (-→*-step e₂-→e₂′ e₂′-→*e₂″) = -→*-step (ξ-·₂ ve₁ e₂-→e₂′) (ξ-·₂* ve₁ e₂′-→*e₂″)
ξ-let⟨⟩₁* : e₁ -→* e₁′ → `let⟨ Δ ⟩ e₁ e₂ -→* `let⟨ Δ ⟩ e₁′ e₂
ξ-let⟨⟩₁* -→*-refl = -→*-refl
ξ-let⟨⟩₁* (-→*-step e₁-→e₁′ e₁′-→*e₁″) = -→*-step (ξ-let⟨⟩₁ e₁-→e₁′) (ξ-let⟨⟩₁* e₁′-→*e₁″)
ξ-wrap* : e -→* e′ → `wrap Δ e -→* `wrap Δ e′
ξ-wrap* -→*-refl = -→*-refl
ξ-wrap* (-→*-step e-→e′ e′-→*e″) = -→*-step (ξ-wrap e-→e′) (ξ-wrap* e′-→*e″)
ξ-letwrap₁* : e₁ -→* e₁′ → `letwrap Δ e₁ e₂ -→* `letwrap Δ e₁′ e₂
ξ-letwrap₁* -→*-refl = -→*-refl
ξ-letwrap₁* (-→*-step e₁-→e₁′ e₁′-→*e₁″) = -→*-step (ξ-letwrap₁ e₁-→e₁′) (ξ-letwrap₁* e₁′-→*e₁″)
Value-substᵈ : ∀ {e : Γ ⊢ A ^ n} {σ : Γ′ ⊩ Γ} {d} (σᵈ : σ ≤ᵈ′ d) → Value e → Value (substᵈ σᵈ e)
Value-substᵈ σᵈ (`λ⟨ Δ ⟩ e) = `λ⟨ Δ ⟩ substᵈ (extsᵈ σᵈ) e
Value-substᵈ σᵈ `true = `true
Value-substᵈ σᵈ `false = `false
Value-substᵈ σᵈ ⟨ e ⟩ = ⟨ substᵈ (exts↾ᵈ σᵈ) e ⟩
Value-substᵈ σᵈ (`wrap Δ e ve) = `wrap Δ (substᵈ (exts++ᵈ (inject₁ Δ) σᵈ) e) (Value-substᵈ (exts++ᵈ (inject₁ Δ) σᵈ) ve)
Value-subst : ∀ {e : Γ ⊢ A ^ n} (σ : Γ′ ⊩ Γ) → Value e → Value (subst σ e)
Value-subst σ ve = Value-substᵈ (≤ᵈ′-refl σ) ve