-- Normalization theorem: -- Show that each typed term has an η-long β-normal form. module Term.Normalization.EtaLong where open import Prelude open import Term open import Term.Weakening renaming (lookup to lookupR) open import Term.Substitution open import Term.Equality open import Term.Weakening.Properties using (wk-id; wk-wk) open import Term.Substitution.Properties using (sub-id; sub-S-sg) private variable Γ Δ Φ : Context α : BaseTy a b : Ty x : a ∈ Γ t t' t'' u u' : Term Γ a σ σ' : Sub Γ Δ ρ : Wk Γ Δ -- Long normal forms, defined inductively. mutual -- Neutrals: no λ in the head. -- Neutrals do not β-reduce -- and do not cause β-redexes when replacing a variable in a term. data Ne : Term Γ a → Set where var : Ne (var x) app : Ne t → Nf u → Ne (app t u) -- Normal forms: only neutral applications. -- For long normal forms, each neutral term is of base type. data Nf : Term Γ a → Set where ne : {t : Term Γ (` α)} → Ne t → Nf t abs : Nf t → Nf (abs t) -- Weakly normalizing terms are equal to a normal form. -- For "wn t" we can also say "t has a normal form". record wne (t : Term Γ a) : Set where constructor wneu field nf : Term Γ a neu : Ne nf reds : t ≅ nf record wn (t : Term Γ a) : Set where constructor wnorm field nf : Term Γ a norm : Nf nf reds : t ≅ nf -- wn/wne have the same closure properties as normal form, -- plus they are closed under equality. mutual wne-var : wne (var x) wne-var = wneu _ var refl wne-app : wne t → wn u → wne (app t u) wne-app (wneu _ neu rt) (wnorm _ nf ru) = wneu _ (app neu nf) (app rt ru) wn-abs : wn t → wn (abs t) wn-abs (wnorm _ nf rs) = wnorm _ (abs nf) (abs rs) wne→wn : {t : Term Γ (` α)} → wne t → wn t wne→wn (wneu _ neu rs) = wnorm _ (ne neu) rs expand-wn : t ≅ t' → wn t' → wn t expand-wn w (wnorm _ nf rs) = wnorm _ nf (≅trans w rs) -- We cannot directly show that each well-typed term has a normal form, -- since this property is not closed under application a priori. -- -- A counterexample does not exist, since they are closed under application -- a posteriori, but it exists in untyped lambda-calculus: -- With δ = λ x → x x we have wn δ, but not wn (δ δ). -- -- To get wn t → wn u → wn (app t u) we need to prove something -- stronger about well-typed terms, namely that they are "reducible". -- Reducibility: Interpreting types as sets of weakly normalizing terms. -- -- In the case of function types, we also require that terms behave -- as "functions" meaning that they map reducible arguments to reducible results. -- -- In that, we need to consider reducible arguments in a larger context -- as we need to be able to apply a λ-term Term Γ (a ⇒ b) -- to a new fresh variable a ∈ (a ∷ Γ) to show that it is weakly normalizing. -- -- So, a term of base type is reducible if it is weakly normalizing. -- A term t : Term Γ (a ⇒ b) of function type is reducible if for each -- weakening ρ : Wk Δ Γ and each reducible argument u : Term Δ a -- the application app (wk ρ t) u of the transported term t to u is reducible. mutual Red : (Γ : Context) (a : Ty) (t : Term Γ a) → Set Red Γ (` α) t = wn t Red Γ (a ⇒ b) t = ∀{Δ} (ρ : Wk Δ Γ) {u : Term Δ a} (⟦u⟧ : Red Δ a u) → Red Δ b (app (wk ρ t) u) -- Reducibility for substitutions: a substitution is reducible if each of its terms is reducible. data Reds Γ : (Δ : Context) (σ : Sub Γ Δ) → Set where [] : Reds Γ [] [] _∷_ : (⟦t⟧ : Red Γ a t) (⟦σ⟧ : Reds Γ Δ σ) → Reds Γ (a ∷ Δ) (t ∷ σ) -- Projecting a term from a reducible substitution. ⟦lookup⟧ : (⟦σ⟧ : Reds Γ Δ σ) (x : a ∈ Δ) → Red Γ a (lookup σ x) ⟦lookup⟧ (⟦t⟧ ∷ _) zero = ⟦t⟧ ⟦lookup⟧ (_ ∷ ⟦σ⟧) (suc x) = ⟦lookup⟧ ⟦σ⟧ x -- Reducibility is closed under weak-head expansion. -- Proof by induction on the type. expand-Red : t ≅ t' → Red Γ a t' → Red Γ a t expand-Red {a = ` α} w wn = expand-wn w wn expand-Red {a = a ⇒ b} w ⟦t⟧ ρ ⟦u⟧ = expand-Red (app (wk-≅ w) refl) (⟦t⟧ ρ ⟦u⟧) -- Normal forms are closed under weakening. -- Proof by induction on the normal form. mutual wk-Ne : (neu : Ne t) → Ne (wk ρ t) wk-Ne var = var wk-Ne (app neu norm) = app (wk-Ne neu) (wk-Nf norm) wk-Nf : (norm : Nf t) → Nf (wk ρ t) wk-Nf (ne neu) = ne (wk-Ne neu) wk-Nf (abs norm) = abs (wk-Nf norm) -- wn and wne are closed under weakening. wk-wne : wne t → wne (wk ρ t) wk-wne (wneu _ neu e) = wneu _ (wk-Ne neu) (wk-≅ e) wk-wn : wn t → wn (wk ρ t) wk-wn (wnorm _ norm e) = wnorm _ (wk-Nf norm) (wk-≅ e) -- Reducibility is closed under weakening. -- Proof by induction on the type. wk-Red : Red Γ a t → Red Δ a (wk ρ t) wk-Red {a = ` α} wn = wk-wn wn wk-Red {a = a ⇒ b} {ρ = ρ} ⟦t⟧ ρ' ⟦u⟧ = subst (λ t → Red _ _ (app t _)) (wk-wk) (⟦t⟧ (compWW ρ' ρ) ⟦u⟧) -- Reducible substitutions are closed under weakening. -- Proven pointwise. wk-Reds : Reds Δ Γ σ → Reds Φ Γ (compWS ρ σ) wk-Reds [] = [] wk-Reds (⟦t⟧ ∷ ⟦σ⟧) = wk-Red ⟦t⟧ ∷ wk-Reds ⟦σ⟧ -- Proving that each well-typed term is reducible still fails in the case of abs -- where we need show that application to an arbitrary reducible argument -- produces a reducible term after β-contraction. -- Thus we need to be able to instantiate variables with reducible terms. -- So we instead prove that each well-typed term is valid where -- "validity" is reducibility under all reducible substitutions. -- Valid terms ("semantic" terms). Valid : {Γ : Context} {a : Ty} (t : Term Γ a) → Set Valid {Γ = Γ} {a = a} t = ∀{Δ}{σ : Sub Δ Γ} (⟦σ⟧ : Reds Δ Γ σ) → Red Δ a (sub σ t) -- Validity is closed under term constructors. -- For variables it is just a projection from the reducible substitution. valid-var : (x : a ∈ Γ) → Valid (var x) valid-var x ⟦σ⟧ = ⟦lookup⟧ ⟦σ⟧ x -- For abstractions, we need to work most: we need β-expansion -- of reduciblity. valid-abs : {t : Term (a ∷ Γ) b} → Valid t → Valid (abs t) valid-abs {a = a} {Γ = Γ} {b = b} {t = t} ⟦t⟧ {σ = σ} ⟦σ⟧ ρ {u = u} ⟦u⟧ = expand-Red (subst (app (wk ρ (sub σ (abs t))) u ≅_) (sub-S-sg {ρ = ρ} {σ = σ} {t = t} {u = u}) β) (⟦t⟧ {σ = u ∷ compWS ρ σ} (⟦u⟧ ∷ wk-Reds ⟦σ⟧)) -- For application, validity holds by definition -- (except for a cast with the identity renaming). valid-app : Valid t → Valid u → Valid (app t u) valid-app {t = t} {u = u} ⟦t⟧ ⟦u⟧ {σ = σ} ⟦σ⟧ = subst (λ t → Red _ _ (app t (sub σ u))) (wk-id {ρ = idW}) (⟦t⟧ ⟦σ⟧ idW {u = sub σ u} (⟦u⟧ ⟦σ⟧)) -- Fundamental theorem: each well-typed term t is "valid". -- By induction on t, all the work has been done already. fund : (t : Term Γ a) → Valid t fund (var x) = valid-var x fund (abs t) = valid-abs {t = t} (fund t) fund (app t u) = valid-app {t = t} {u = u} (fund t) (fund u) -- To get from a valid term to a reducible term, we need to apply -- it to a reducible substitution. -- If we apply it to the identity substitution, the term will not change, -- so we need to show that the identity substitution is reducible. -- It is sufficient to show that variables are reducible. -- But since we reason by induction on types, -- we need to more generally show that each neutral term is reducible (wne→Red). -- -- Simultaneously we show that each reducible term is weakly normalizing, -- ("the escape lemma" Red→wn), -- which we will also use in the final theorem. -- This uses the fact that Red is closed under η-reduction. mutual wne→Red : {t : Term Γ a} → wne t → Red Γ a t wne→Red {a = ` α} wne = wne→wn wne wne→Red {a = a ⇒ b} ⟦t⟧ ρ ⟦u⟧ = wne→Red (wne-app (wk-wne ⟦t⟧) (Red→wn ⟦u⟧)) Red→wn : {t : Term Γ a} → Red Γ a t → wn t Red→wn {a = ` α} wn = wn Red→wn {a = a ⇒ b} ⟦t⟧ = expand-wn η (wn-abs (Red→wn (⟦t⟧ skip1 ⟦var0⟧))) ⟦var0⟧ : Red (a ∷ Γ) a (var zero) ⟦var0⟧ {a = a} = wne→Red wne-var -- The identity substitution is reducible. ⟦idS⟧ : Reds Γ Γ idS ⟦idS⟧ {Γ = []} = [] ⟦idS⟧ {Γ = a ∷ Γ} = ⟦var0⟧ ∷ wk-Reds ⟦idS⟧ -- Normalization theorem: each well-typed term t is weakly normalizing. -- -- Proof steps: -- * t is valid by the fundamental theorem. -- * sub idS t is reducible by instantiation with the identity substitution. -- * sub idS t is weakly normalizing. -- * t is weakly normalizing. normalization : (t : Term Γ a) → wn t normalization t = subst wn (sub-id) (Red→wn (fund t ⟦idS⟧)) -- Q.E.D. -- Not used: Reducible substitutions are closed under lifting. ⟦lift⟧ : (⟦σ⟧ : Reds Δ Γ σ) → Reds (a ∷ Δ) (a ∷ Γ) (lift σ) ⟦lift⟧ ⟦σ⟧ = ⟦var0⟧ ∷ wk-Reds ⟦σ⟧