module A201606.STLC.CoinductiveNormalisationByEvaluation where

open import A201606.Common.Delay public
open import A201606.Common.OrderPreservingEmbedding public
open import A201606.STLC.Syntax public


-- Normal terms, neutral terms, and spines.

mutual
  data No (Γ : Cx Ty) : Ty  Set where
    lamₙ  :  {A B}  No (Γ , A) B  No Γ (A  B)
    pairₙ :  {A B}  No Γ A  No Γ B  No Γ (A  B)
    unitₙ : No Γ 
    neₙ   : Ne No Γ ι  No Γ ι

  data Ne (Ξ : Cx Ty  Ty  Set) (Γ : Cx Ty) : Ty  Set where
    varₙ :  {A}  A  Γ  Ne Ξ Γ A
    appₙ :  {A B}  Ne Ξ Γ (A  B)  Ξ Γ A  Ne Ξ Γ B
    fstₙ :  {A B}  Ne Ξ Γ (A  B)  Ne Ξ Γ A
    sndₙ :  {A B}  Ne Ξ Γ (A  B)  Ne Ξ Γ B

  data Val (Γ : Cx Ty) : Ty  Set where
    lamᵥ  :  {A B Γᶜ}  Env Γ Γᶜ  Tm (Γᶜ , A) B  Val Γ (A  B)
    pairᵥ :  {A B}  Val Γ A  Val Γ B  Val Γ (A  B)
    unitᵥ : Val Γ 
    neᵥ   :  {A}  Ne Val Γ A  Val Γ A

  data Env (Γ : Cx Ty) : Cx Ty  Set where
       : Env Γ 
    _,_ :  {A Γᶜ}  Env Γ Γᶜ  Val Γ A  Env Γ (Γᶜ , A)


-- Weakening.

mutual
  ren-no :  {Γ Γ′}  Γ  Γ′  Ren No Γ Γ′
  ren-no ρ (lamₙ t)    = lamₙ (ren-no (keep ρ) t)
  ren-no ρ (pairₙ t u) = pairₙ (ren-no ρ t) (ren-no ρ u)
  ren-no ρ unitₙ       = unitₙ
  ren-no ρ (neₙ t)     = neₙ (ren-nen ρ t)

  ren-nen :  {Γ Γ′}  Γ  Γ′  Ren (Ne No) Γ Γ′
  ren-nen ρ (varₙ i)   = varₙ (ren-var ρ i)
  ren-nen ρ (appₙ t u) = appₙ (ren-nen ρ t) (ren-no ρ u)
  ren-nen ρ (fstₙ t)   = fstₙ (ren-nen ρ t)
  ren-nen ρ (sndₙ t)   = sndₙ (ren-nen ρ t)

  ren-nev :  {Γ Γ′}  Γ  Γ′  Ren (Ne Val) Γ Γ′
  ren-nev ρ (varₙ i)   = varₙ (ren-var ρ i)
  ren-nev ρ (appₙ t u) = appₙ (ren-nev ρ t) (ren-val ρ u)
  ren-nev ρ (fstₙ t)   = fstₙ (ren-nev ρ t)
  ren-nev ρ (sndₙ t)   = sndₙ (ren-nev ρ t)

  ren-val :  {Γ Γ′}  Γ  Γ′  Ren Val Γ Γ′
  ren-val ρ (lamᵥ γ t)  = lamᵥ (ren-env ρ γ) t
  ren-val ρ (pairᵥ t u) = pairᵥ (ren-val ρ t) (ren-val ρ u)
  ren-val ρ unitᵥ       = unitᵥ
  ren-val ρ (neᵥ t)     = neᵥ (ren-nev ρ t)

  ren-env :  {Γ Γ′}  Γ  Γ′  Ren Env Γ Γ′
  ren-env ρ        = 
  ren-env ρ (γ , t) = ren-env ρ γ , ren-val ρ t

wk-val :  {A Γ}  Ren Val Γ (Γ , A)
wk-val = ren-val (skip refl⊆)

wk-env :  {A Γ}  Ren Env Γ (Γ , A)
wk-env = ren-env (skip refl⊆)


-- Soundness.

lookup :  {A Γ Γᶜ}  Env Γ Γᶜ  A  Γᶜ  Val Γ A
lookup        ()
lookup (γ , t) top     = t
lookup (γ , u) (pop i) = lookup γ i

reduce∧₁ :  {A B Γ i}  Val Γ (A  B)  Delay i (Val Γ A)
reduce∧₁ (pairᵥ t u) = now t
reduce∧₁ (neᵥ t)     = now (neᵥ (fstₙ t))

reduce∧₂ :  {A B Γ i}  Val Γ (A  B)  Delay i (Val Γ B)
reduce∧₂ (pairᵥ t u) = now u
reduce∧₂ (neᵥ t)     = now (neᵥ (sndₙ t))

mutual
  eval :  {A Γ Γᶜ i}  Env Γ Γᶜ  Tm Γᶜ A  Delay i (Val Γ A)
  eval γ (var i)    = now (lookup γ i)
  eval γ (lam t)    = now (lamᵥ γ t)
  eval γ (app t u)  = t′  eval γ t 
                      u′  eval γ u 
                      reduce⊃ t′ u′
  eval γ (pair t u) = t′  eval γ t 
                      u′  eval γ u 
                      now (pairᵥ t′ u′)
  eval γ (fst t)    = t′  eval γ t 
                      reduce∧₁ t′
  eval γ (snd t)    = t′  eval γ t 
                      reduce∧₂ t′
  eval γ unit       = now unitᵥ

  ∞eval :  {A Γ Γᶜ i}  Env Γ Γᶜ  Tm Γᶜ A  ∞Delay i (Val Γ A)
  force (∞eval γ t) = eval γ t

  reduce⊃ :  {A B Γ i}  Val Γ (A  B)  Val Γ A  Delay i (Val Γ B)
  reduce⊃ (lamᵥ γ t) u = later (∞eval (γ , u) t)
  reduce⊃ (neᵥ t)    u = now (neᵥ (appₙ t u))


-- Completeness.

mutual
  quot :  {A Γ i}  Val Γ A  Delay i (No Γ A)
  quot {ι}     (neᵥ t) = neₙ <$> quotₙ t
  quot {A  B} t       = later (∞expand⊃ t)
  quot {A  B} t       = later (∞expand∧ t)
  quot {}    t       = now unitₙ

  quotₙ :  {A Γ i}  Ne Val Γ A  Delay i (Ne No Γ A)
  quotₙ (varₙ i)   = now (varₙ i)
  quotₙ (appₙ t u) = t′  quotₙ t 
                     u′  quot u 
                     now (appₙ t′ u′)
  quotₙ (fstₙ t)   = t′  quotₙ t 
                     now (fstₙ t′)
  quotₙ (sndₙ t)   = t′  quotₙ t 
                     now (sndₙ t′)

  ∞expand⊃ :  {A B Γ i}  Val Γ (A  B)  ∞Delay i (No Γ (A  B))
  force (∞expand⊃ t) = t′  reduce⊃ (wk-val t) (neᵥ (varₙ top)) 
                       t″  quot t′ 
                       now (lamₙ t″)

  ∞expand∧ :  {A B Γ i}  Val Γ (A  B)  ∞Delay i (No Γ (A  B))
  force (∞expand∧ t) = t₁′  reduce∧₁ t 
                       t₂′  reduce∧₂ t 
                       t₁″  quot t₁′ 
                       t₂″  quot t₂′ 
                       now (pairₙ t₁″ t₂″)


-- Normalisation.

refl-env :  {Γ}  Env Γ Γ
refl-env {}     = 
refl-env {γ , t} = wk-env refl-env , neᵥ (varₙ top)

norm? :  {A Γ}  Tm Γ A  Delay  (No Γ A)
norm? t = t′  eval refl-env t 
          quot t′