-- 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 ⟦σ⟧