module A201802.WIP.LR3-Mutual where

open import A201801.Prelude
open import A201801.Category
open import A201801.Fin
open import A201801.FinLemmas
open import A201801.Vec
open import A201801.VecLemmas
open import A201801.AllVec

open import A201802.LR0
open import A201802.LR0Lemmas
open import A201802.LR1
open import A201802.LR2 -- TODO: which LR2?


--------------------------------------------------------------------------------


-- -- `SN _ A` is the strong normalisation predicate on terms at type `A`.
-- mutual
--   SN : Term 0 → Type → Set
--   SN M A = ∙ ⊢ M ⦂ A × M ⇓ × SN! M A

--   SN! : Term 0 → Type → Set
--   SN! M 𝔹       = ⊤
--   SN! M 𝟙       = ⊤
--   SN! M (A ∧ B) = ⊤
--   SN! M (A ⊃ B) = ∀ {N} → SN N A → SN (APP M N) B


-- -- Every SN term is well-typed.
-- derp : ∀ {A M} → SN M A
--                → ∙ ⊢ M ⦂ A
-- derp (𝒟 , M⇓ , s!) = 𝒟


-- -- Every SN term terminates.
-- herp : ∀ {A M} → SN M A
--                → M ⇓
-- herp (𝒟 , M⇓ , s!) = M⇓


-- --------------------------------------------------------------------------------


-- -- Small-step reduction IN REVERSE preserves SN.
-- mutual
--   snpr⤇ : ∀ {A M M′} → M ⤇ M′ → ∙ ⊢ M ⦂ A → SN M′ A
--                       → SN M A
--   snpr⤇ M⤇M′ 𝒟 (𝒟′ , M′⇓ , s!′) = 𝒟 , hpr⤇ M⤇M′ M′⇓ , sn!pr⤇ M⤇M′ 𝒟 s!′

--   sn!pr⤇ : ∀ {A M M′} → M ⤇ M′ → ∙ ⊢ M ⦂ A → SN! M′ A
--                        → SN! M A
--   sn!pr⤇ {𝔹}     M⤇M′ 𝒟 ∙   = ∙
--   sn!pr⤇ {𝟙}     M⤇M′ 𝒟 ∙   = ∙
--   sn!pr⤇ {A ∧ B} M⤇M′ 𝒟 ∙   = ∙
--   sn!pr⤇ {A ⊃ B} M⤇M′ 𝒟 f s = snpr⤇ (cong-APP M⤇M′) (app 𝒟 (derp s)) (f s)


-- -- Iterated small-step reduction IN REVERSE preserves SN.
-- snpr⤇* : ∀ {A M M′} → M ⤇* M′ → ∙ ⊢ M ⦂ A → SN M′ A
--                      → SN M A
-- snpr⤇* done                 𝒟 s = s
-- snpr⤇* (step M⤇M″ M″⤇*M′) 𝒟 s = snpr⤇ M⤇M″ 𝒟 (snpr⤇* M″⤇*M′ (tp⤇ M⤇M″ 𝒟) s)


-- -- Big-step reduction IN REVERSE preserves SN.
-- snpr⇓ : ∀ {A M M′} → M ⇓ M′ → ∙ ⊢ M ⦂ A → SN M′ A
--                    → SN M A
-- snpr⇓ (M⤇*M′ , VM′) 𝒟 s = snpr⤇* M⤇*M′ 𝒟 s


-- -- If `M` is SN and `N` is SN, then `PAIR M N` is SN.
-- sn-PAIR : ∀ {A B M N} → SN M A → SN N B
--                       → SN (PAIR M N) (A ∧ B)
-- sn-PAIR (𝒟 , M⇓ , s!₁) (ℰ , N⇓ , s!₂) = pair 𝒟 ℰ , halt-PAIR M⇓ N⇓ , ∙


-- -- ???
-- mutual
--   sn-FST-PAIR : ∀ {A B M M′ N′} → {{_ : Val M′}} {{_ : Val N′}}
--                                 → M ⤇* PAIR M′ N′ → ∙ ⊢ M ⦂ A ∧ B
--                                 → SN (FST M) A
--   sn-FST-PAIR M⤇*PAIR 𝒟 = fst 𝒟 , halt-FST-PAIR M⤇*PAIR , sn!-FST-PAIR M⤇*PAIR 𝒟

--   sn!-FST-PAIR : ∀ {A B M M′ N′} → {{_ : Val M′}} {{_ : Val N′}}
--                                  → M ⤇* PAIR M′ N′ → ∙ ⊢ M ⦂ A ∧ B
--                                  → SN! (FST M) A
--   sn!-FST-PAIR {𝔹}       M⤇*PAIR 𝒟   = ∙
--   sn!-FST-PAIR {𝟙}       M⤇*PAIR 𝒟   = ∙
--   sn!-FST-PAIR {A₁ ∧ A₂} M⤇*PAIR 𝒟   = ∙
--   sn!-FST-PAIR {A₁ ⊃ A₂} M⤇*PAIR 𝒟 s = {!!}
--   -- snpr⤇* (congs-APP (reds-FST-PAIR M⤇*PAIR)) (app (fst 𝒟) (derp s)) ?


-- -- ???
-- mutual
--   sn-SND-PAIR : ∀ {A B M M′ N′} → {{_ : Val M′}} {{_ : Val N′}}
--                                 → M ⤇* PAIR M′ N′ → ∙ ⊢ M ⦂ A ∧ B
--                                 → SN (SND M) B
--   sn-SND-PAIR M⤇*PAIR 𝒟 = snd 𝒟 , halt-SND-PAIR M⤇*PAIR , sn!-SND-PAIR M⤇*PAIR 𝒟

--   sn!-SND-PAIR : ∀ {B A M M′ N′} → {{_ : Val M′}} {{_ : Val N′}}
--                                  → M ⤇* PAIR M′ N′ → ∙ ⊢ M ⦂ A ∧ B
--                                  → SN! (SND M) B
--   sn!-SND-PAIR {𝔹}       M⤇*PAIR 𝒟   = ∙
--   sn!-SND-PAIR {𝟙}       M⤇*PAIR 𝒟   = ∙
--   sn!-SND-PAIR {B₁ ∧ B₂} M⤇*PAIR 𝒟   = ∙
--   sn!-SND-PAIR {B₁ ⊃ B₂} M⤇*PAIR 𝒟 s = {!!}
--   -- snpr⤇* (congs-APP (reds-SND-PAIR M⤇*PAIR)) (app (snd 𝒟) (derp s)) ?


-- -- If `M` reduces to `TRUE` and `N` is SN, then `IF M N O` is SN.
-- mutual
--   sn-IF-TRUE : ∀ {C M N O} → M ⤇* TRUE → ∙ ⊢ M ⦂ 𝔹 → SN N C → ∙ ⊢ O ⦂ C
--                            → SN (IF M N O) C
--   sn-IF-TRUE M⤇*TRUE 𝒟 (ℰ , N⇓ , s!) ℱ = if 𝒟 ℰ ℱ , halt-IF-TRUE M⤇*TRUE N⇓ , sn!-IF-TRUE M⤇*TRUE 𝒟 ℰ ℱ s!

--   sn!-IF-TRUE : ∀ {C M N O} → M ⤇* TRUE → ∙ ⊢ M ⦂ 𝔹 → ∙ ⊢ N ⦂ C → ∙ ⊢ O ⦂ C → SN! N C
--                             → SN! (IF M N O) C
--   sn!-IF-TRUE {𝔹}     M⤇*TRUE 𝒟 ℰ ℱ ∙   = ∙
--   sn!-IF-TRUE {𝟙}     M⤇*TRUE 𝒟 ℰ ℱ ∙   = ∙
--   sn!-IF-TRUE {A ∧ B} M⤇*TRUE 𝒟 ℰ ℱ ∙   = ∙
--   sn!-IF-TRUE {A ⊃ B} M⤇*TRUE 𝒟 ℰ ℱ f s = snpr⤇* (congs-APP (reds-IF-TRUE M⤇*TRUE done)) (app (if 𝒟 ℰ ℱ) (derp s)) (f s)


-- -- If `M` reduces to `FALSE` and `O` is SN, then `IF M N O` is SN.
-- mutual
--   sn-IF-FALSE : ∀ {C M N O} → M ⤇* FALSE → ∙ ⊢ M ⦂ 𝔹 → ∙ ⊢ N ⦂ C → SN O C
--                             → SN (IF M N O) C
--   sn-IF-FALSE M⤇*FALSE 𝒟 ℰ (ℱ , N⇓ , s!) = if 𝒟 ℰ ℱ , halt-IF-FALSE M⤇*FALSE N⇓ , sn!-IF-FALSE M⤇*FALSE 𝒟 ℰ ℱ s!

--   sn!-IF-FALSE : ∀ {C M N O} → M ⤇* FALSE → ∙ ⊢ M ⦂ 𝔹 → ∙ ⊢ N ⦂ C → ∙ ⊢ O ⦂ C → SN! O C
--                              → SN! (IF M N O) C
--   sn!-IF-FALSE {𝔹}     M⤇*FALSE 𝒟 ℰ ℱ ∙   = ∙
--   sn!-IF-FALSE {𝟙}     M⤇*FALSE 𝒟 ℰ ℱ ∙   = ∙
--   sn!-IF-FALSE {A ∧ B} M⤇*FALSE 𝒟 ℰ ℱ ∙   = ∙
--   sn!-IF-FALSE {A ⊃ B} M⤇*FALSE 𝒟 ℰ ℱ f s = snpr⤇* (congs-APP (reds-IF-FALSE M⤇*FALSE done)) (app (if 𝒟 ℰ ℱ) (derp s)) (f s)


-- --------------------------------------------------------------------------------


-- -- Small-step reduction preserves SN.
-- mutual
--   snp⤇ : ∀ {A M M′} → M ⤇ M′ → ∙ ⊢ M ⦂ A → SN M A
--                      → SN M′ A
--   snp⤇ M⤇M′ 𝒟 (_ , M⇓ , s!) = tp⤇ M⤇M′ 𝒟 , hp⤇ M⤇M′ M⇓ , sn!p⤇ M⤇M′ 𝒟 s!

--   sn!p⤇ : ∀ {A M M′} → M ⤇ M′ → ∙ ⊢ M ⦂ A → SN! M A
--                       → SN! M′ A
--   sn!p⤇ {𝔹}     M⤇M′ 𝒟 ∙   = ∙
--   sn!p⤇ {𝟙}     M⤇M′ 𝒟 ∙   = ∙
--   sn!p⤇ {A ∧ B} M⤇M′ 𝒟 ∙   = ∙
--   sn!p⤇ {A ⊃ B} M⤇M′ 𝒟 f s = snp⤇ (cong-APP M⤇M′) (app 𝒟 (derp s)) (f s)


-- -- Iterated small-step reduction preserves SN.
-- snp⤇* : ∀ {A M M′} → M ⤇* M′ → ∙ ⊢ M ⦂ A → SN M A
--                     → SN M′ A
-- snp⤇* done                 𝒟 s = s
-- snp⤇* (step M⤇M″ M″⤇*M′) 𝒟 s = snp⤇* M″⤇*M′ (tp⤇ M⤇M″ 𝒟) (snp⤇ M⤇M″ 𝒟 s)


-- -- Big-step reduction preserves SN.
-- snp⇓ : ∀ {A M M′} → M ⇓ M′ → ∙ ⊢ M ⦂ A → SN M A
--                   → SN M′ A
-- snp⇓ (M⤇*M′ , VM′) 𝒟 s = snp⤇* M⤇*M′ 𝒟 s


-- --------------------------------------------------------------------------------


-- -- `SNs Γ` is the strong normalisation predicate on substitutions at all types `Γ`.
-- SNs : ∀ {g} → (τ : Terms 0 g) → Types g → Set
-- SNs τ Γ = All (\ { (M , A) → SN M A }) (zip τ Γ)


-- -- Every SN substitution is well-typed.
-- derps : ∀ {g} → {τ : Terms 0 g} {Γ : Types g}
--               → SNs τ Γ
--               → ∙ ⊢ τ ⦂ Γ all
-- derps σ = maps derp σ


-- --------------------------------------------------------------------------------


-- -- TODO
-- red-APP-LAM-SUB : ∀ {g M N} → {τ : Terms 0 g} → {{_ : Val N}}
--                             → APP (LAM (SUB (LIFTS τ) M)) N ⤇ SUB (τ , N) M
-- red-APP-LAM-SUB {M = M} {N} {τ} rewrite simp-CUT-SUB N τ M ⁻¹ = red APP-LAM


-- -- TODO
-- big-red-APP-LAM-SUB : ∀ {g M M′ N} → {τ : Terms 0 g} → {{_ : Vals τ}} {{_ : Val N}}
--                                    → SUB (τ , N) M ⇓ M′
--                                    → APP (LAM (SUB (LIFTS τ) M)) N ⇓ M′
-- big-red-APP-LAM-SUB {M = M} (SUB⤇*M′ , VM′) = step (red-APP-LAM-SUB {M = M}) SUB⤇*M′ , VM′


-- -- TODO
-- halt-APP-LAM-SUB : ∀ {g M N} → {τ : Terms 0 g} → {{_ : Vals τ}} {{_ : Val N}}
--                              → SUB (τ , N) M ⇓
--                              → APP (LAM (SUB (LIFTS τ) M)) N ⇓
-- halt-APP-LAM-SUB {M = M} (M′ , SUB⇓M′) = M′ , big-red-APP-LAM-SUB {M = M} SUB⇓M′


-- -- TODO
-- mutual
--   sn-APP-LAM-SUB : ∀ {B g M N A} → {τ : Terms 0 g} → {{_ : Vals τ}} {{_ : Val N}}
--                                  → ∙ ⊢ SUB τ (LAM M) ⦂ A ⊃ B → ∙ ⊢ N ⦂ A → SN (SUB (τ , N) M) B
--                                  → SN (APP (LAM (SUB (LIFTS τ) M)) N) B
--   sn-APP-LAM-SUB {M = M} 𝒟 ℰ (𝒟′ , SUB⇓ , s!) = app 𝒟 ℰ , halt-APP-LAM-SUB {M = M} SUB⇓ , sn!-APP-LAM-SUB {M = M} 𝒟 ℰ s!

--   sn!-APP-LAM-SUB : ∀ {B g M N A} → {τ : Terms 0 g} → {{_ : Vals τ}} {{_ : Val N}}
--                                   → ∙ ⊢ SUB τ (LAM M) ⦂ A ⊃ B → ∙ ⊢ N ⦂ A → SN! (SUB (τ , N) M) B
--                                   → SN! (APP (LAM (SUB (LIFTS τ) M)) N) B
--   sn!-APP-LAM-SUB {𝔹}       {M = M} 𝒟 ℰ ∙   = ∙
--   sn!-APP-LAM-SUB {𝟙}       {M = M} 𝒟 ℰ ∙   = ∙
--   sn!-APP-LAM-SUB {B₁ ∧ B₂} {M = M} 𝒟 ℰ ∙   = ∙
--   sn!-APP-LAM-SUB {B₁ ⊃ B₂} {M = M} 𝒟 ℰ f s = snpr⤇ (cong-APP (red-APP-LAM-SUB {M = M})) (app (app 𝒟 ℰ) (derp s)) (f s)


-- --------------------------------------------------------------------------------


-- mutual
--   sn-SUB : ∀ {g M A} → {τ : Terms 0 g} {Γ : Types g} → {{_ : Vals τ}}
--                      → SNs τ Γ → Γ ⊢ M ⦂ A
--                      → SN (SUB τ M) A
--   sn-SUB σ (var i)    = get σ (zip∋₂ i)
--   sn-SUB σ (lam 𝒟)    = let 𝒟′ = sub (derps σ) (lam 𝒟) in
--                           𝒟′ , (LAM _ , done , VLAM) , sn-SUB-LAM σ 𝒟 𝒟′
--   sn-SUB σ (app 𝒟 ℰ)  with sn-SUB σ 𝒟
--   sn-SUB σ (app 𝒟 ℰ)  | 𝒟′ , M′⇓ , f = f (sn-SUB σ ℰ)
--   sn-SUB σ (pair 𝒟 ℰ) = sn-PAIR (sn-SUB σ 𝒟) (sn-SUB σ ℰ)
--   sn-SUB σ (fst 𝒟)    with sn-SUB σ 𝒟
--   sn-SUB σ (fst 𝒟)    | 𝒟′ , (M′       , SUB⤇*M′   , VM′)    , ∙ with tp⤇* SUB⤇*M′ 𝒟′
--   sn-SUB σ (fst 𝒟)    | 𝒟′ , (LAM _    , _          , VLAM)   , ∙ | ()
--   sn-SUB σ (fst 𝒟)    | 𝒟′ , (UNIT     , _          , VUNIT)  , ∙ | ()
--   sn-SUB σ (fst 𝒟)    | 𝒟′ , (PAIR _ _ , SUB⤇*PAIR , VPAIR)  , ∙ | pair _ _ = sn-FST-PAIR SUB⤇*PAIR 𝒟′
--   sn-SUB σ (fst 𝒟)    | 𝒟′ , (TRUE     , _          , VTRUE)  , ∙ | ()
--   sn-SUB σ (fst 𝒟)    | 𝒟′ , (FALSE    , _          , VFALSE) , ∙ | ()
--   sn-SUB σ (snd 𝒟)    with sn-SUB σ 𝒟
--   sn-SUB σ (snd 𝒟)    | 𝒟′ , (M′       , SUB⤇*M′   , VM′)    , ∙ with tp⤇* SUB⤇*M′ 𝒟′
--   sn-SUB σ (snd 𝒟)    | 𝒟′ , (LAM _    , _          , VLAM)   , ∙ | ()
--   sn-SUB σ (snd 𝒟)    | 𝒟′ , (UNIT     , _          , VUNIT)  , ∙ | ()
--   sn-SUB σ (snd 𝒟)    | 𝒟′ , (PAIR _ _ , SUB⤇*PAIR , VPAIR)  , ∙ | pair _ _ = sn-SND-PAIR SUB⤇*PAIR 𝒟′
--   sn-SUB σ (snd 𝒟)    | 𝒟′ , (TRUE     , _          , VTRUE)  , ∙ | ()
--   sn-SUB σ (snd 𝒟)    | 𝒟′ , (FALSE    , _          , VFALSE) , ∙ | ()
--   sn-SUB σ unit       = unit  , (UNIT  , done , VUNIT)  , ∙
--   sn-SUB σ true       = true  , (TRUE  , done , VTRUE)  , ∙
--   sn-SUB σ false      = false , (FALSE , done , VFALSE) , ∙
--   sn-SUB σ (if 𝒟 ℰ ℱ) with sn-SUB σ 𝒟
--   sn-SUB σ (if 𝒟 ℰ ℱ) | 𝒟′ , (M′       , SUB⤇*M′    , VM′)    , ∙ with tp⤇* SUB⤇*M′ 𝒟′
--   sn-SUB σ (if 𝒟 ℰ ℱ) | 𝒟′ , (LAM _    , _           , VLAM)   , ∙ | ()
--   sn-SUB σ (if 𝒟 ℰ ℱ) | 𝒟′ , (UNIT     , _           , VUNIT)  , ∙ | ()
--   sn-SUB σ (if 𝒟 ℰ ℱ) | 𝒟′ , (PAIR _ _ , _           , VPAIR)  , ∙ | ()
--   sn-SUB σ (if 𝒟 ℰ ℱ) | 𝒟′ , (TRUE     , SUB⤇*TRUE  , VTRUE)  , ∙ | true  = sn-IF-TRUE SUB⤇*TRUE 𝒟′ (sn-SUB σ ℰ) (sub (derps σ) ℱ)
--   sn-SUB σ (if 𝒟 ℰ ℱ) | 𝒟′ , (FALSE    , SUB⤇*FALSE , VFALSE) , ∙ | false = sn-IF-FALSE SUB⤇*FALSE 𝒟′ (sub (derps σ) ℰ) (sn-SUB σ ℱ)

--   sn-SUB-LAM : ∀ {g M N A B} → {τ : Terms 0 g} {Γ : Types g} → {{_ : Vals τ}}
--                              → SNs τ Γ → Γ , A ⊢ M ⦂ B → ∙ ⊢ LAM (SUB (LIFTS τ) M) ⦂ A ⊃ B → SN N A
--                              → SN (APP (LAM (SUB (LIFTS τ) M)) N) B
--   sn-SUB-LAM {M = M} {{Vτ}} σ 𝒟 𝒟′ s@(ℰ , (N′ , N⇓N′@(N⤇*N′ , VN′)) , s!)
--     = let s′ = snp⇓ N⇓N′ ℰ s in
--         snpr⤇* (congs-APP-LAM N⤇*N′) (app 𝒟′ ℰ) (sn-APP-LAM-SUB {M = M} {{Vτ}} {{VN′}} 𝒟′ (derp s′) (sn-SUB {{Vτ , VN′}} (σ , s′) 𝒟))


-- --------------------------------------------------------------------------------


-- -- Every well-typed term is SN.
-- sn : ∀ {A M} → ∙ ⊢ M ⦂ A
--              → SN M A
-- sn {A} {M} 𝒟 = subst (\ M′ → SN M′ A) (id-SUB M) (sn-SUB ∙ 𝒟)


-- -- Every well-typed term terminates.
-- halt : ∀ {A M} → ∙ ⊢ M ⦂ A
--                → M ⇓
-- halt {A} 𝒟 = herp {A} (sn 𝒟)


-- --------------------------------------------------------------------------------