{-# OPTIONS --rewriting #-}

module A201801.CMLEnlightenment where


open import A201801.Prelude
open import A201801.Category
open import A201801.List
open import A201801.ListLemmas
open import A201801.ListConcatenation
open import A201801.AllList
open import A201801.CMLPropositions
import A201801.CMLStandardDerivations as CML


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


infix 3 _⊢_valid[_]
data _⊢_valid[_] : List Assert  Form  List Form  Set
  where
    vz :  {A Δ Γ}  Δ  A valid[ Γ , A ]

    wk :  {A B Δ Γ}  Δ  A valid[ Γ ]
                      Δ  A valid[ Γ , B ]

    lam :  {A B Δ Γ}  Δ  B valid[ Γ , A ]
                       Δ  A  B valid[ Γ ]

    app :  {A B Δ Γ}  Δ  A  B valid[ Γ ]  Δ  A valid[ Γ ]
                       Δ  B valid[ Γ ]

    mvz! :  {A Ψ Δ}   Δ ,  Ψ  A   A valid[ Ψ ]

    mwk :  {B Ψ A Δ Γ}  Δ  A valid[ Γ ]
                         Δ ,  Ψ  B   A valid[ Γ ]

    box :  {A Ψ Δ Γ}  Δ  A valid[ Ψ ]
                       Δ  [ Ψ ] A valid[ Γ ]

    letbox :  {A B Ψ Δ Γ}  Δ  [ Ψ ] A valid[ Γ ]  Δ ,  Ψ  A   B valid[ Γ ]
                            Δ  B valid[ Γ ]


infix 3 _⊢_allvalid[_]
_⊢_allvalid[_] : List Assert  List Form  List Form  Set
Δ  Ξ allvalid[ Γ ] = All (\ A  Δ  A valid[ Γ ]) Ξ


infix 3 _⊢_allvalid*
_⊢_allvalid* : List Assert  List Assert  Set
Δ  Ξ allvalid* = All (\ {  Γ  A   Δ  A valid[ Γ ] }) Ξ


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


wks :  {A Δ Γ Ξ}  Δ  Ξ allvalid[ Γ ]
                   Δ  Ξ allvalid[ Γ , A ]
wks ξ = maps wk ξ


lifts :  {A Δ Γ Ξ}  Δ  Ξ allvalid[ Γ ]
                     Δ  Ξ , A allvalid[ Γ , A ]
lifts ξ = wks ξ , vz


vars :  {Δ Γ Γ′}  Γ′  Γ
                   Δ  Γ allvalid[ Γ′ ]
vars done     = 
vars (drop η) = wks (vars η)
vars (keep η) = lifts (vars η)


ids :  {Δ Γ}  Δ  Γ allvalid[ Γ ]
ids = vars id


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


mwks :  {A Ψ Δ Γ Ξ}  Δ  Ξ allvalid[ Γ ]
                      Δ ,  Ψ  A   Ξ allvalid[ Γ ]
mwks ξ = maps mwk ξ


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


lams :  {Δ Γ A}  (Ξ : List Form)  Δ  A valid[ Γ  Ξ ]
                  Δ  Ξ ⊃⋯⊃ A valid[ Γ ]
lams        𝒟 = 𝒟
lams (Ξ , B) 𝒟 = lams Ξ (lam 𝒟)


unlam :  {Δ Γ A B}  Δ  A  B valid[ Γ ]
                     Δ  B valid[ Γ , A ]
unlam 𝒟 = app (wk 𝒟) vz


unlams :  {Δ Γ A}  (Ξ : List Form)  Δ  Ξ ⊃⋯⊃ A valid[ Γ ]
                    Δ  A valid[ Γ  Ξ ]
unlams        𝒟 = 𝒟
unlams (Ξ , B) 𝒟 = unlam (unlams Ξ 𝒟)


apps :  {Δ Γ Ξ A}  Δ  Ξ ⊃⋯⊃ A valid[ Γ ]  Δ  Ξ allvalid[ Γ ]
                    Δ  A valid[ Γ ]
apps 𝒟        = 𝒟
apps 𝒟 (ξ , ) = app (apps 𝒟 ξ) 


blam :  {Δ Γ Ψ A B}  Δ  [ Ψ , A ] B valid[ Γ ]
                      Δ  [ Ψ ] (A  B) valid[ Γ ]
blam 𝒟 = letbox 𝒟 (box (lam mvz!))


unblam :  {Δ Γ Ψ A B}  Δ  [ Ψ ] (A  B) valid[ Γ ]
                        Δ  [ Ψ , A ] B valid[ Γ ]
unblam 𝒟 = letbox 𝒟 (box (unlam mvz!))


blams :  {Δ Γ Ψ A}  (Ξ : List Form)  Δ  [ Ψ  Ξ ] A valid[ Γ ]
                     Δ  [ Ψ ] (Ξ ⊃⋯⊃ A) valid[ Γ ]
blams        𝒟 = 𝒟
blams (Ξ , B) 𝒟 = blams Ξ (blam 𝒟)


unblams :  {Δ Γ Ψ A}  (Ξ : List Form)  Δ  [ Ψ ] (Ξ ⊃⋯⊃ A) valid[ Γ ]
                       Δ  [ Ψ  Ξ ] A valid[ Γ ]
unblams        𝒟 = 𝒟
unblams (Ξ , B) 𝒟 = unblam (unblams Ξ 𝒟)


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


var :  {Δ Γ A}  Γ  A
                 Δ  A valid[ Γ ]
var zero    = vz
var (suc i) = wk (var i)


vau :  {Δ Γ Ψ A B}  Δ ,  Ψ  A   B valid[ Γ ]
                     Δ  B valid[ Γ , [ Ψ ] A ]
vau 𝒟 = letbox vz (wk 𝒟)


unvau :  {Δ Γ Ψ A B}  Δ  B valid[ Γ , [ Ψ ] A ]
                       Δ ,  Ψ  A   B valid[ Γ ]
unvau 𝒟 = app (lam (mwk 𝒟)) (box mvz!)


vaus :  {Δ Γ Ψ Ξ A}  Δ ,  Ψ  A   Ξ allvalid[ Γ ]
                      Δ  Ξ allvalid[ Γ , [ Ψ ] A ]
vaus 𝒟 = maps vau 𝒟


mvar! :  {Δ Ψ A}  Δ   Ψ  A 
                   Δ  A valid[ Ψ ]
mvar! zero    = mvz!
mvar! (suc i) = mwk (mvar! i)


-- TODO: unfinished
-- mvar : ∀ {A Ψ Δ Γ} → Δ ∋ ⟪ Ψ ⊫ A ⟫ → Δ ⊢ Ψ allvalid[ Γ ]
--                    → Δ ⊢ A valid[ Γ ]
-- mvar {Ψ = Ψ} i ψ = {!mvar! i!}


unbox :  {Δ Ψ A}  Δ  [ Ψ ] A valid[ Ψ ]
                   Δ  A valid[ Ψ ]
unbox 𝒟 = letbox 𝒟 mvz!


-- TODO: unfinished
-- sub : ∀ {Δ Γ Ξ A} → Δ ⊢ Ξ allvalid[ Γ ] → Δ ⊢ A valid[ Ξ ]
--                   → Δ ⊢ A valid[ Γ ]
-- sub (ξ , 𝒞) vz           = 𝒞
-- sub (ξ , 𝒞) (wk 𝒟)       = sub ξ 𝒟
-- sub ξ       (lam 𝒟)      = lam (sub (lifts ξ) 𝒟)
-- sub ξ       (app 𝒟 ℰ)    = app (sub ξ 𝒟) (sub ξ ℰ)
-- sub ξ       mvz!         = {!unbox (unvau vz)!}
-- sub ξ       (mwk 𝒟)      = unvau (sub (vaus ξ) 𝒟)
-- sub ξ       (box 𝒟)      = box 𝒟
-- sub ξ       (letbox 𝒟 ℰ) = letbox (sub ξ 𝒟) (sub (mwks ξ) ℰ)


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


⟦_⟧ :  {Δ Γ A}  Δ  A valid[ Γ ]
                 Δ CML.⊢ A valid[ Γ ]
 vz          = CML.vz
 wk 𝒟        = CML.wk  𝒟 
 lam 𝒟       = CML.lam  𝒟 
 app 𝒟      = CML.app  𝒟    
-- ⟦ mvar i ⟧     = CML.mvar i CML.ids
 mvz!        = CML.mvz CML.ids
 mwk 𝒟       = CML.mwk  𝒟 
 box 𝒟       = CML.box  𝒟 
 letbox 𝒟   = CML.letbox  𝒟    


-- TODO: unfinished
-- mutual
--   ↓ : ∀ {Δ Γ A} → Δ CML.⊢ A valid[ Γ ]
--                 → Δ ⊢ A valid[ Γ ]
--   ↓ (CML.var i)      = var i
--   ↓ (CML.lam 𝒟)      = lam (↓ 𝒟)
--   ↓ (CML.app 𝒟 ℰ)    = app (↓ 𝒟) (↓ ℰ)
--   ↓ (CML.mvar i ψ)   = sub (↓ⁿ ψ) (mvar! i)
--   ↓ (CML.box 𝒟)      = box (↓ 𝒟)
--   ↓ (CML.letbox 𝒟 ℰ) = letbox (↓ 𝒟) (↓ ℰ)
--
--   ↓ⁿ : ∀ {Δ Γ Ξ} → Δ CML.⊢ Ξ allvalid[ Γ ]
--                  → Δ ⊢ Ξ allvalid[ Γ ]
--   ↓ⁿ ∙       = ∙
--   ↓ⁿ (ξ , 𝒟) = ↓ⁿ ξ , ↓ 𝒟


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