-- Typed βη equality for the simply typed lambda calculus.
--
-- β would be the same for the untyped lambda calculus,
-- but for η it is convenient that we have the type information.
module Term.Equality where
open import Prelude
open import Term
open import Term.Weakening
open import Term.Substitution
open import Term.Weakening.Properties using (wk1-wk)
open import Term.Substitution.Properties using (wk-sg; sub-sg; wk1-sub)
private
variable
Γ Δ : Context
a b : Ty
t t' t'' t₁ t₂ t₃ u u' : Term Γ a
σ σ' : Sub Γ Δ
ρ ρ' : Wk Γ Δ
infix 1 _≅_
-- t ≅ t' is the congruence generated by axioms from β and η,
-- congruence meaning that it is an equivalence relation (refl, trans, sym)
-- and closed under all term constructors (abs, app).
--
-- Closure under weakening and substitution is proven subsequently.
data _≅_ : (t t' : Term Γ a) → Set where
β : app (abs t) u ≅ t [ u ]₀
η : {t : Term Γ (a ⇒ b)} → t ≅ abs (app (wk1 t) (var zero))
abs : (et : t ≅ t') → abs t ≅ abs t'
app : (et : t ≅ t') (eu : u ≅ u') → app t u ≅ app t' u'
refl : t ≅ t
≅trans : (e₁ : t₁ ≅ t₂) (e₂ : t₂ ≅ t₃) → t₁ ≅ t₃
≅sym : (e : t ≅ t') → t' ≅ t
-- Closure of t ≅ t' under weakening.
--
-- Proof by induction on t ≅ t'.
-- Only the base cases (β and η) are interesting, they need properties
-- about weakening and substitution.
wk-≅ : t ≅ t' → wk ρ t ≅ wk ρ t'
-- Case β-contraction: Show wk ρ (app (abs t) u) ≅ wk ρ (t [ u ]₀).
-- By definition of wk: wk ρ (app (abs t) u) = app (abs (wk (keep ρ) t)) (wk ρ u)
-- Thus, β gives: wk ρ (app (abs t) u) ≅ (wk (keep ρ) t) [ wk ρ u ]₀
-- We need the fact that wk over the single substitution,
-- wk-sg : (wk (keep ρ) t) [ wk ρ u ]₀ ≡ wk ρ (t [ u ]₀)
-- to conclude the proof by a cast ("subst").
wk-≅ {ρ = ρ} (β {t = t} {u = u}) =
subst
(app (abs (wk (keep ρ) t)) (wk ρ u) ≅_)
(wk-sg {t = t}) -- wk (keep ρ) t) [ wk ρ u ]₀ ≡ wk ρ (t [ u ]₀)
β
-- Case η-expansion: Show wk ρ t ≅ wk ρ (abs (app (wk1 t) (var zero)))
-- = abs (wk (keep ρ) (app (wk1 t) (var zero)))
-- = abs (app (wk (keep ρ) (wk1 t)) (wk (keep ρ) (var zero)))
-- = abs (app (wk (keep ρ) (wk1 t)) (var (lookup (keep ρ) zero)))
-- = abs (app (wk (keep ρ) (wk1 t)) (var zero))
-- η gives wk ρ t ≅ abs (app (wk1 (wk ρ t)) (var zero)
-- So we need to cast with wk1-wk : wk1 (wk ρ t) ≡ wk (keep ρ) (wk1 t).
wk-≅ {ρ = ρ} (η {t = t}) =
subst
(λ u → wk ρ t ≅ abs (app u (var zero)))
wk1-wk
(η {t = wk ρ t})
-- Other cases by induction hypothesis:
wk-≅ (abs e) = abs (wk-≅ e)
wk-≅ (app e e₁) = app (wk-≅ e) (wk-≅ e₁)
wk-≅ refl = refl
wk-≅ (≅trans e e₁) = ≅trans (wk-≅ e) (wk-≅ e₁)
wk-≅ (≅sym e) = ≅sym (wk-≅ e)
-- Closure of t ≅ t' under substitution.
--
-- Proof by induction on t ≅ t'.
-- Only the base cases (β and η) are interesting, they need the substitution laws.
sub-≡ : t ≅ t' → sub σ t ≅ sub σ t'
-- Case β-contraction: sub σ (app (abs t) u) ≅ sub σ (t [ u ]₀)
sub-≡ {σ = σ} (β {t = t} {u = u}) =
subst
(app (abs (sub (lift σ) t)) (sub σ u) ≅_)
(sym (sub-sg {σ = σ} {t = t} {u = u}))
β
-- Case η-expansion: sub σ t ≅ sub σ (abs (app (wk1 t) (var zero)))
sub-≡ {σ = σ} (η {t = t}) =
subst
(λ u → sub σ t ≅ abs (app u (var zero)))
(wk1-sub {σ = σ} {t = t})
(η {t = sub σ t})
-- Other cases by induction hypothesis:
sub-≡ {σ = σ} (abs e) = abs (sub-≡ e)
sub-≡ {σ = σ} (app e e₁) = app (sub-≡ e) (sub-≡ e₁)
sub-≡ {σ = σ} refl = refl
sub-≡ {σ = σ} (≅trans e e₁) = ≅trans (sub-≡ e) (sub-≡ e₁)
sub-≡ {σ = σ} (≅sym e) = ≅sym (sub-≡ e)