-- Weak β normalization
--
-- Goal: each well-typed term β-reduces to a weak normal form
module Term.Normalization.Weak where
open import Prelude
open import Prelude.Reduction
open import Term
open import Term.Weakening renaming (lookup to lookupR)
open import Term.Weakening.Properties using (wk-id; wk-wk)
open import Term.Substitution
open import Term.Substitution.Properties using (sub-id; sub-S-sg; wk-sg; contraction-after-weakening)
open import Term.Reduction
open import Term.Reduction.Properties
open import Term.Reduction.Standard
open import Term.NormalForm
private
variable
Γ Δ Ξ : Context
a b c : Ty
x : a ∈ Γ
t t' t'' u u' : Term Γ a
σ σ' : Sub Γ Δ
ρ : Wk Γ Δ
-- Weakly normalizing terms standard-reduce 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 ⟶s nf
record wn (t : Term Γ a) : Set where
constructor wnorm
field
{nf} : Term Γ a
norm : Nf nf
reds : t ⟶s nf
-- wn/wne have the same closure properties as normal forms.
wne-var : wne (var x)
wne-var = wneu var reflS
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 Γ a} → wne t → wn t
wne→wn (wneu neu rs) = wnorm (ne neu) rs
-- Plus they are closed under expansion.
whd-wne : t ⟶w t' → wne t' → wne t
whd-wne w (wneu neu s) = wneu neu (w ∷ s)
whd-wn : t ⟶w t' → wn t' → wn t
whd-wn w (wnorm nf s) = wnorm nf (w ∷ s)
expand-wn : t ⟶s t' → wn t' → wn t
expand-wn s (wnorm nf rs) = wnorm nf (transS s rs)
-- Inductive characterization of weakly normalizing terms:
-- The minimal predicate with the above closure properties.
mutual
data WNe : Term Γ a → Set where
var : WNe (var x)
app : (wne : WNe t) (wn : WN u) → WNe (app t u)
data WN : Term Γ a → Set where
ne : (wne : WNe t) → WN t
abs : (wn : WN t) → WN (abs t)
exp : (w : t ⟶w t') (wn : WN t') → WN t
-- Closure under weakening
mutual
wk-WNe : (ρ : Wk Γ Δ) {t : Term Δ a} → WNe t → WNe (wk ρ t)
wk-WNe ρ var = var
wk-WNe ρ (app wne wn) = app (wk-WNe ρ wne) (wk-WN ρ wn)
wk-WN : (ρ : Wk Γ Δ) {t : Term Δ a} → WN t → WN (wk ρ t)
wk-WN ρ (ne wne) = ne (wk-WNe ρ wne)
wk-WN ρ (abs wn) = abs (wk-WN (keep ρ) wn)
wk-WN ρ (exp w wn) = exp (wkW w) (wk-WN ρ wn)
------------------------------------------------------------------------
-- Soundness of the inductive characterization
-- The inductive characterization is sound.
-- Proof by induction on WNe/WN, using the closure properties of wne/wn.
mutual
WNe→wne : WNe t → wne t
WNe→wne var = wne-var
WNe→wne (app wne wn) = wne-app (WNe→wne wne) (WN→wn wn)
WN→wn : WN t → wn t
WN→wn (ne wne) = wne→wn (WNe→wne wne)
WN→wn (abs wn) = wn-abs (WN→wn wn)
WN→wn (exp w wn) = whd-wn w (WN→wn wn)
------------------------------------------------------------------------
-- Completeness of the inductive characterization
-- We first show that Ne/Nf is contained in WNe/WN,
-- then we show that the latter are closed under expansion
-- with standard reduction sequences.
-- For WNe, this is actually not true, so we define a relaxed WNe*
-- that is closed under weak-head expansion.
data WNe* (t : Term Γ a) : Set where
wne* : {t' : Term Γ a} (wne : WNe t') (ws : t ⟶w* t') → WNe* t
-- record WNe* (t : Term Γ a) : Set where
-- constructor wne*
-- field
-- {ne-t} : Term Γ a
-- isWNe : WNe ne-t
-- reds : t ⟶w* ne-t
-- Step 1 of completeness:
-- A normal form is trivially weakly normalizing, even inductively
mutual
Ne→WNe : Ne t → WNe t
Ne→WNe var = var
Ne→WNe (app neu nf) = app (Ne→WNe neu) (Nf→WN nf)
Nf→WN : Nf t → WN t
Nf→WN (ne neu) = ne (Ne→WNe neu)
Nf→WN (abs nf) = abs (Nf→WN nf)
-- Step 2 of completeness:
-- WN is closed under expansion
-- WN is closed under multiple weak head expansions.
-- Trivial induction on the weak head expansion sequence.
whd*-WN : t ⟶w* t' → WN t' → WN t
whd*-WN [] wn = wn
whd*-WN (w ∷ ws) wn = exp w (whd*-WN ws wn)
-- WN is closed under expansion with standard reduction sequences.
mutual
-- If t ⟶s t' and WNe t' then WNe* t.
-- By induction on t ⟶s t'.
expand-WNe : t ⟶s t' → WNe t' → WNe* t
expand-WNe (w ∷ s) d with expand-WNe s d
... | wne* wne ws = wne* wne (w ∷ ws)
expand-WNe var d = wne* d []
expand-WNe (abs s) ()
expand-WNe (app s s₁) (app wne wn) with expand-WNe s wne | expand-WN s₁ wn
... | wne* wne' ws | wn' = wne* (app wne' wn') (applW* ws)
-- If t ⟶s t' and WN t' then WN t.
-- By main induction on WN t' and side induction on t ⟶s t'.
expand-WN : t ⟶s t' → WN t' → WN t
expand-WN (w ∷ s) wn = exp w (expand-WN s wn)
expand-WN s (exp w wn) = expand-WN (snocSW s w) wn
expand-WN s (ne wne) with expand-WNe s wne
... | wne* wne ws = whd*-WN ws (ne wne)
expand-WN (abs s) (abs wn) = abs (expand-WN s wn)
-- Putting steps 1 and 2 together gives our completeness theorem:
-- The inductive characterization is complete.
wne→WNe : wne t → WNe* t
wne→WNe (wneu neu rs) = expand-WNe rs (Ne→WNe neu)
wn→WN : wn t → WN t
wn→WN (wnorm nf rs) = expand-WN rs (Nf→WN nf)
------------------------------------------------------------------------
-- Strengthening weak normalization
-- We need that WN (app t x) implies WN t if x does not appear in t.
-- First, we prove that if a weakened term weak-head reduces,
-- so does its original form.
whd-strengthen : wk ρ t ⟶w t' → ∃ λ u → (t ⟶w u) × (wk ρ u ≡ t')
whd-strengthen {t = app (var x) u} (appl ())
whd-strengthen {t = app (abs t) u} β = t [ u ]₀ , β , ≡.sym (wk-sg {t = t})
-- Need: wk ρ (t [ u ]₀) ≡ wk (keep ρ) t [ wk ρ u ]₀
whd-strengthen {t = app (app t u₁) u₂} (appl r) with whd-strengthen r
... | _ , r' , refl = _ , appl r' , refl
-- We prove that weakened WN terms are still WN if you drop the weakening.
mutual
WNe-strengthen : WNe (wk ρ t) → WNe t
WNe-strengthen {t = var x} var = var
WNe-strengthen {t = abs t} ()
WNe-strengthen {t = app t u} (app wne wn) = app (WNe-strengthen wne) (WN-strengthen wn)
WN-strengthen : WN (wk ρ t) → WN t
WN-strengthen {t = abs t} (abs wn) = abs (WN-strengthen wn)
WN-strengthen (ne wne) = ne (WNe-strengthen wne)
WN-strengthen (exp w wn) with whd-strengthen w
... | _ , w' , refl = exp w' (WN-strengthen wn)
-- Lemma: if WN (app (↑ t) x₀) then WN t.
WN-η-contract : ∀ {t : Term Γ (a ⇒ b)} → WN (app (wk (skip idW) t) (var zero)) → WN t
WN-η-contract (ne (app wne _)) = ne (WNe-strengthen wne)
WN-η-contract {t = var x} (exp (appl ()) wn)
WN-η-contract {t = abs t} (exp β wn) = abs (≡.subst WN contraction-after-weakening wn)
WN-η-contract {t = app t t₁} (exp (appl w) wn) with whd-strengthen w
... | _ , w' , refl = exp w' (WN-η-contract wn)
------------------------------------------------------------------------
-- Normalization proof by reducibility.
--
-- We refine the Kripke-Model of our normalization-by-evaluation proof
-- by to the reducibility logical relation.
-- This way, we can prove that the normal form computed by the soundness
-- proof of the STLC is indeed a (standard) reduct of the original term.
--
-- The goal is: if Γ ⊢ t : a then t ⟶s t' for some normal t'.
--
-- By soundness of WN this becomes: if Γ ⊢ t : a then WN t.
--
-- 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 Γ ε ε
_∙_ : (⟦σ⟧ : Reds Γ Δ σ) (⟦t⟧ : Red Γ a t) → 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.
whd-Red : t ⟶w t' → Red Γ a t' → Red Γ a t
whd-Red {a = ` α} w wn = exp w wn
whd-Red {a = a ⇒ b} w ⟦t⟧ ρ ⟦u⟧ = whd-Red (appl (wkW w)) (⟦t⟧ ρ ⟦u⟧)
-- 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-Reds ⟦σ⟧ ∙ wk-Red ⟦t⟧
-- 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⟧ =
whd-Red
(subst
(app (wk ρ (sub σ (abs t))) u ⟶w_)
(sub-S-sg {ρ = ρ} {σ = σ} {t = t} {u = u})
β)
(⟦t⟧ {σ = compWS ρ σ ∙ u} (wk-Reds ⟦σ⟧ ∙ ⟦u⟧))
-- 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
-- This is the equivalent to reflection.
WNe→Red : {t : Term Γ a} → WNe t → Red Γ a t
WNe→Red {a = ` α} wne = ne wne
WNe→Red {a = a ⇒ b} ⟦t⟧ ρ ⟦u⟧ = WNe→Red (app (wk-WNe ρ ⟦t⟧) (Red→WN ⟦u⟧))
-- This is the equivalent to reification.
Red→WN : {t : Term Γ a} → Red Γ a t → WN t
Red→WN {a = ` α} wn = wn
Red→WN {a = a ⇒ b} ⟦t⟧ = WN-η-contract (Red→WN (⟦t⟧ skip1 ⟦var0⟧))
-- Reflection of the 0th variable.
⟦var0⟧ : Red (Γ ∙ a) a (var zero)
⟦var0⟧ {a = a} = WNe→Red var
-- The identity substitution is reducible.
⟦idS⟧ : Reds Γ Γ idS
⟦idS⟧ {Γ = ε} = ε
⟦idS⟧ {Γ = Γ ∙ a} = wk-Reds ⟦idS⟧ ∙ ⟦var0⟧
-- 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⟧ ⟦σ⟧ = wk-Reds ⟦σ⟧ ∙ ⟦var0⟧
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}
-- -}