{-# OPTIONS --rewriting #-}

module A201706.ISMLSyntaxNoTerms where

open import A201706.ISML public
open ISMLList public


-- Contexts.

Cx : Set
Cx = BoxTy⋆  Ty⋆


-- Derivations.

mutual
  infix 3 _⊢_
  data _⊢_ : Cx  Ty  Set where
    var   :  {Δ Γ A} 
              Γ  A 
              Δ  Γ  A
    mvar  :  {Δ Γ Φ Ψ A} 
              Δ   ⊢⧆ Φ  Δ  Γ ⊢⋆ Ψ  Δ  [ Φ  Ψ ] A 
              Δ  Γ  A
    lam   :  {Δ Γ A B} 
              Δ  Γ , A  B 
              Δ  Γ  A  B
    app   :  {Δ Γ A B} 
              Δ  Γ  A  B  Δ  Γ  A 
              Δ  Γ  B
    box   :  {Δ Γ Φ Ψ A} 
              Φ  Ψ  A 
              Δ  Γ  [ Φ  Ψ ] A
    unbox :  {Δ Γ Φ Ψ A C} 
              Δ  Γ  [ Φ  Ψ ] A  Δ , [ Φ  Ψ ] A  Γ  C 
              Δ  Γ  C

  infix 3 _⊢⧆_
  data _⊢⧆_ : Cx  BoxTy⋆  Set where
       :  {Δ Γ} 
            Δ  Γ ⊢⧆ 
    _,_ :  {Δ Γ Φ Ψ Ξ A} 
            Δ  Γ ⊢⧆ Ξ  Δ  Γ  [ Φ  Ψ ] A 
            Δ  Γ ⊢⧆ Ξ , [ Φ  Ψ ] A

  infix 3 _⊢⋆_
  _⊢⋆_ : Cx  Ty⋆  Set
  Δ  Γ ⊢⋆ Ξ = All (Δ  Γ ⊢_) Ξ

mutual
  mono⊢ :  {Δ Γ Δ′ Γ′ A}  Δ′  Δ  Γ′  Γ  Δ  Γ  A  Δ′  Γ′  A
  mono⊢ ζ η (var 𝒾)      = var (mono∋ η 𝒾)
  mono⊢ ζ η (mvar φ ψ 𝒾) = mvar (mono⊢⧆ ζ done φ) (mono⊢⋆ ζ η ψ) (mono∋ ζ 𝒾)
  mono⊢ ζ η (lam 𝒟)      = lam (mono⊢ ζ (lift η) 𝒟)
  mono⊢ ζ η (app 𝒟 )    = app (mono⊢ ζ η 𝒟) (mono⊢ ζ η )
  mono⊢ ζ η (box 𝒟)      = box 𝒟
  mono⊢ ζ η (unbox 𝒟 )  = unbox (mono⊢ ζ η 𝒟) (mono⊢ (lift ζ) η )

  mono⊢⧆ :  {Δ Γ Δ′ Γ′ Ξ}  Δ′  Δ  Γ′  Γ  Δ  Γ ⊢⧆ Ξ  Δ′  Γ′ ⊢⧆ Ξ
  mono⊢⧆ ζ η        = 
  mono⊢⧆ ζ η (ξ , 𝒟) = mono⊢⧆ ζ η ξ , mono⊢ ζ η 𝒟

  mono⊢⋆ :  {Δ Γ Δ′ Γ′ Ξ}  Δ′  Δ  Γ′  Γ  Δ  Γ ⊢⋆ Ξ  Δ′  Γ′ ⊢⋆ Ξ
  mono⊢⋆ ζ η        = 
  mono⊢⋆ ζ η (ξ , 𝒟) = mono⊢⋆ ζ η ξ , mono⊢ ζ η 𝒟
  -- NOTE: Equivalent, but does not pass termination check.
  -- mono⊢⋆ ζ η ξ = mapAll (mono⊢ ζ η) ξ

mutual
  idmono⊢ :  {Δ Γ A}  (𝒟 : Δ  Γ  A)  mono⊢ refl⊇ refl⊇ 𝒟  𝒟
  idmono⊢ (var 𝒾)      = cong var (idmono∋ 𝒾)
  idmono⊢ (mvar φ ψ 𝒾) = cong³ mvar (idmono⊢⧆ φ) (idmono⊢⋆ ψ) (idmono∋ 𝒾)
  idmono⊢ (lam 𝒟)      = cong lam (idmono⊢ 𝒟)
  idmono⊢ (app 𝒟 )    = cong² app (idmono⊢ 𝒟) (idmono⊢ )
  idmono⊢ (box 𝒟)      = refl
  idmono⊢ (unbox 𝒟 )  = cong² unbox (idmono⊢ 𝒟) (idmono⊢ )

  idmono⊢⧆ :  {Δ Γ Ξ}  (ξ : Δ  Γ ⊢⧆ Ξ)  mono⊢⧆ refl⊇ refl⊇ ξ  ξ
  idmono⊢⧆        = refl
  idmono⊢⧆ (ξ , 𝒟) = cong² _,_ (idmono⊢⧆ ξ) (idmono⊢ 𝒟)

  idmono⊢⋆ :  {Δ Γ Ξ}  (ξ : Δ  Γ ⊢⋆ Ξ)  mono⊢⋆ refl⊇ refl⊇ ξ  ξ
  idmono⊢⋆        = refl
  idmono⊢⋆ (ξ , 𝒟) = cong² _,_ (idmono⊢⋆ ξ) (idmono⊢ 𝒟)

-- NOTE: Needs {-# REWRITE idtrans⊇₁ #-}.
mutual
  assocmono⊢ :  {Δ Γ Δ′ Γ′ Γ″ Δ″ A} 
                  (ζ′ : Δ″  Δ′) (η′ : Γ″  Γ′) (ζ : Δ′  Δ) (η : Γ′  Γ) (𝒟 : Δ  Γ  A) 
                  mono⊢ ζ′ η′ (mono⊢ ζ η 𝒟)  mono⊢ (trans⊇ ζ′ ζ) (trans⊇ η′ η) 𝒟
  assocmono⊢ ζ′ η′ ζ η (var 𝒾)      = cong var (assocmono∋ η′ η 𝒾)
  assocmono⊢ ζ′ η′ ζ η (mvar φ ψ 𝒾) = cong³ mvar (assocmono⊢⧆ ζ′ done ζ done φ) (assocmono⊢⋆ ζ′ η′ ζ η ψ) (assocmono∋ ζ′ ζ 𝒾)
  assocmono⊢ ζ′ η′ ζ η (lam 𝒟)      = cong lam (assocmono⊢ ζ′ (lift η′) ζ (lift η) 𝒟)
  assocmono⊢ ζ′ η′ ζ η (app 𝒟 )    = cong² app (assocmono⊢ ζ′ η′ ζ η 𝒟) (assocmono⊢ ζ′ η′ ζ η )
  assocmono⊢ ζ′ η′ ζ η (box 𝒟)      = refl
  assocmono⊢ ζ′ η′ ζ η (unbox 𝒟 )  = cong² unbox (assocmono⊢ ζ′ η′ ζ η 𝒟) (assocmono⊢ (lift ζ′) η′ (lift ζ) η )

  assocmono⊢⧆ :  {Δ Γ Δ′ Γ′ Γ″ Δ″ Ξ} 
                    (ζ′ : Δ″  Δ′) (η′ : Γ″  Γ′) (ζ : Δ′  Δ) (η : Γ′  Γ) (ξ : Δ  Γ ⊢⧆ Ξ) 
                    mono⊢⧆ ζ′ η′ (mono⊢⧆ ζ η ξ)  mono⊢⧆ (trans⊇ ζ′ ζ) (trans⊇ η′ η) ξ
  assocmono⊢⧆ ζ′ η′ ζ η        = refl
  assocmono⊢⧆ ζ′ η′ ζ η (ξ , 𝒟) = cong² _,_ (assocmono⊢⧆ ζ′ η′ ζ η ξ) (assocmono⊢ ζ′ η′ ζ η 𝒟)

  assocmono⊢⋆ :  {Δ Γ Δ′ Γ′ Γ″ Δ″ Ξ} 
                   (ζ′ : Δ″  Δ′) (η′ : Γ″  Γ′) (ζ : Δ′  Δ) (η : Γ′  Γ) (ξ : Δ  Γ ⊢⋆ Ξ) 
                   mono⊢⋆ ζ′ η′ (mono⊢⋆ ζ η ξ)  mono⊢⋆ (trans⊇ ζ′ ζ) (trans⊇ η′ η) ξ
  assocmono⊢⋆ ζ′ η′ ζ η        = refl
  assocmono⊢⋆ ζ′ η′ ζ η (ξ , 𝒟) = cong² _,_ (assocmono⊢⋆ ζ′ η′ ζ η ξ) (assocmono⊢ ζ′ η′ ζ η 𝒟)

refl⊢⋆ :  {Δ Γ}  Δ  Γ ⊢⋆ Γ
refl⊢⋆ {Γ = }     = 
refl⊢⋆ {Γ = Γ , A} = mono⊢⋆ refl⊇ (weak refl⊇) refl⊢⋆ , var zero

-- TODO: Should Telescopic Δ always be required?
Telescopic : BoxTy⋆  Set
Telescopic                  = 
Telescopic (Δ , [ Φ  Ψ ] A) = Telescopic Δ  Δ   ⊢⧆ Φ  Δ   ⊢⋆ Ψ

-- -- TODO: How did this go wrong?
-- postulate
--   oops : ∀ {Δ Γ Φ Ψ A} → Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ [ Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ] A →
--                           Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ [ Φ ⁏ Ψ ] A
--
-- -- TODO: What is going on here?
-- -- Goal: Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ [ Φ ⁏ Ψ ] A
-- -- Have: Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ [ Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ] A
-- mrefl⊢⧆ : ∀ {Δ Γ} → Telescopic Δ → Δ ⁏ Γ ⊢⧆ Δ
-- mrefl⊢⧆ {∅}               {Γ} ∅           = ∅
-- mrefl⊢⧆ {Δ , [ Φ ⁏ Ψ ] A} {Γ} (τ , φ , ψ) =
--   mono⊢⧆ (weak refl⊇) refl⊇ (mrefl⊢⧆ τ) ,
--   oops
--     (box {Δ , [ Φ ⁏ Ψ ] A} {Γ}
--       (mvar {Δ , [ Φ ⁏ Ψ ] A} {Γ} (mono⊢⧆ (weak refl⊇) done φ)
--                                   (mono⊢⋆ (weak refl⊇) inf⊇ ψ) zero))

lookup⊢ :  {Δ Γ Ξ A}  Δ  Γ ⊢⋆ Ξ  Ξ  A  Δ  Γ  A
lookup⊢ ξ 𝒾 = lookupAll ξ 𝒾

mlookup⊢ :  {Δ Γ Ξ Φ Ψ A}  Δ  Γ ⊢⧆ Ξ  Ξ  [ Φ  Ψ ] A  Δ  Γ  [ Φ  Ψ ] A
mlookup⊢ (ξ , 𝒟) zero    = 𝒟
mlookup⊢ (ξ , ) (suc 𝒾) = mlookup⊢ ξ 𝒾

mutual
  graft⊢ :  {Δ Γ Ψ A}  Δ  Γ ⊢⋆ Ψ  Δ  Ψ  A  Δ  Γ  A
  graft⊢ ψ (var 𝒾)       = lookup⊢ ψ 𝒾
  graft⊢ ψ (mvar φ ψ′ 𝒾) = mvar φ (graft⊢⋆ ψ ψ′) 𝒾
  graft⊢ ψ (lam 𝒟)       = lam (graft⊢ (mono⊢⋆ refl⊇ (weak refl⊇) ψ , var zero) 𝒟)
  graft⊢ ψ (app 𝒟 )     = app (graft⊢ ψ 𝒟) (graft⊢ ψ )
  graft⊢ ψ (box 𝒟)       = box 𝒟
  graft⊢ ψ (unbox 𝒟 )   = unbox (graft⊢ ψ 𝒟) (graft⊢ (mono⊢⋆ (weak refl⊇) refl⊇ ψ) )

  graft⊢⋆ :  {Δ Γ Ψ Ξ}  Δ  Γ ⊢⋆ Ψ  Δ  Ψ ⊢⋆ Ξ  Δ  Γ ⊢⋆ Ξ
  graft⊢⋆ ψ        = 
  graft⊢⋆ ψ (ξ , 𝒟) = graft⊢⋆ ψ ξ , graft⊢ ψ 𝒟
  -- NOTE: Equivalent, but does not pass termination check.
  -- graft⊢⋆ ψ ξ = mapAll (graft⊢ ψ) ξ

trans⊢⋆ :  {Δ Γ Γ′ Γ″}  Δ  Γ″ ⊢⋆ Γ′  Δ  Γ′ ⊢⋆ Γ  Δ  Γ″ ⊢⋆ Γ
trans⊢⋆ = graft⊢⋆

-- -- TODO: What is going on here?
-- -- Goal:     Δ , [ Φ ⁏ Ψ ] A ⁏ ∅ ⊢ [ Φ ⁏ Ψ ] A
-- -- Have:     Δ , [ Φ ⁏ Ψ ] A ⁏ ∅ ⊢ [ Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ] A
-- -- Subgoal₁: Δ , [ Φ ⁏ Ψ ] A ⁏ ∅ ⊢⧆ Φ
-- -- Subgoal₂: Δ , [ Φ ⁏ Ψ ] A ⁏ ∅ ⊢⋆ Ψ
-- mutual
--   mgraft⊢ : ∀ {Δ Γ Φ A} → Δ ⁏ ∅ ⊢⧆ Φ → Φ ⁏ Γ ⊢ A → Δ ⁏ Γ ⊢ A
--   mgraft⊢ φ (var 𝒾)       = var 𝒾
--   mgraft⊢ φ (mvar φ′ ψ 𝒾) = unbox (mono⊢ refl⊇ inf⊇ (mlookup⊢ φ 𝒾))
--                                    (mvar (mgraft⊢⧆ (mono⊢⧆ (weak refl⊇) refl⊇ φ) φ′)
--                                          (mgraft⊢⋆ (mono⊢⧆ (weak refl⊇) refl⊇ φ) ψ) zero)
--   mgraft⊢ φ (lam 𝒟)       = lam (mgraft⊢ φ 𝒟)
--   mgraft⊢ φ (app 𝒟 ℰ)     = app (mgraft⊢ φ 𝒟) (mgraft⊢ φ ℰ)
--   mgraft⊢ φ (box 𝒟)       = box 𝒟
--   mgraft⊢ {Δ} {Γ} φ (unbox {Φ = Φ} {Ψ} {A} 𝒟 ℰ) =
--     unbox (mgraft⊢ φ 𝒟)
--           (mgraft⊢ (mono⊢⧆ (weak refl⊇) refl⊇ φ ,
--                      oops (box {Δ , [ Φ ⁏ Ψ ] A} {∅}
--                        (mvar {Δ , [ Φ ⁏ Ψ ] A} {∅} {!!} {!!} zero))) ℰ)
--
--   mgraft⊢⧆ : ∀ {Δ Γ Φ Ξ} → Δ ⁏ ∅ ⊢⧆ Φ → Φ ⁏ Γ ⊢⧆ Ξ → Δ ⁏ Γ ⊢⧆ Ξ
--   mgraft⊢⧆ φ ∅       = ∅
--   mgraft⊢⧆ φ (ξ , 𝒟) = mgraft⊢⧆ φ ξ , mgraft⊢ φ 𝒟
--
--   mgraft⊢⋆ : ∀ {Δ Γ Φ Ξ} → Δ ⁏ ∅ ⊢⧆ Φ → Φ ⁏ Γ ⊢⋆ Ξ → Δ ⁏ Γ ⊢⋆ Ξ
--   mgraft⊢⋆ φ ∅       = ∅
--   mgraft⊢⋆ φ (ξ , 𝒟) = mgraft⊢⋆ φ ξ , mgraft⊢ φ 𝒟
--   -- NOTE: Equivalent, but does not pass termination check.
--   -- mgraft⊢⋆ φ ξ = mapAll (mgraft⊢ φ) ξ
--
-- mtrans⊢⧆ : ∀ {Δ Δ′ Δ″} → Δ″ ⁏ ∅ ⊢⧆ Δ′ → Δ′ ⁏ ∅ ⊢⧆ Δ → Δ″ ⁏ ∅ ⊢⧆ Δ
-- mtrans⊢⧆ = mgraft⊢⧆


-- Normal forms.

mutual
  infix 3 _⊢ⁿᶠ_
  data _⊢ⁿᶠ_ : Cx  Ty  Set where
    lamⁿᶠ   :  {Δ Γ A B} 
                Δ  Γ , A ⊢ⁿᶠ B 
                Δ  Γ ⊢ⁿᶠ A  B
    boxⁿᶠ   :  {Δ Γ Φ Ψ A} 
                Φ  Ψ  A 
                Δ  Γ ⊢ⁿᶠ [ Φ  Ψ ] A
    neⁿᶠ    :  {Δ Γ A} 
                Δ  Γ ⊢ⁿᵉ A 
                Δ  Γ ⊢ⁿᶠ A

  infix 3 _⊢ⁿᵉ_
  data _⊢ⁿᵉ_ : Cx  Ty  Set where
    varⁿᵉ   :  {Δ Γ A} 
                Γ  A 
                Δ  Γ ⊢ⁿᵉ A
    mvarⁿᵉ  :  {Δ Γ Φ Ψ A} 
                Δ   ⊢⧆ Φ  Δ  Γ ⊢⋆ Ψ  Δ  [ Φ  Ψ ] A 
                Δ  Γ ⊢ⁿᵉ A
    appⁿᵉ   :  {Δ Γ A B} 
                Δ  Γ ⊢ⁿᵉ A  B  Δ  Γ ⊢ⁿᶠ A 
                Δ  Γ ⊢ⁿᵉ B
    unboxⁿᵉ :  {Δ Γ Φ Ψ A C} 
                Δ  Γ ⊢ⁿᵉ [ Φ  Ψ ] A  Δ , [ Φ  Ψ ] A  Γ ⊢ⁿᶠ C 
                Δ  Γ ⊢ⁿᵉ C

infix 3 _⊢⋆ⁿᵉ_
_⊢⋆ⁿᵉ_ : Cx  Ty⋆  Set
Δ  Γ ⊢⋆ⁿᵉ Ξ = All (Δ  Γ ⊢ⁿᵉ_) Ξ

mutual
  mono⊢ⁿᶠ :  {Δ Γ Δ′ Γ′ A}  Δ′  Δ  Γ′  Γ  Δ  Γ ⊢ⁿᶠ A  Δ′  Γ′ ⊢ⁿᶠ A
  mono⊢ⁿᶠ ζ η (lamⁿᶠ 𝒟)      = lamⁿᶠ (mono⊢ⁿᶠ ζ (lift η) 𝒟)
  mono⊢ⁿᶠ ζ η (boxⁿᶠ 𝒟)      = boxⁿᶠ 𝒟
  mono⊢ⁿᶠ ζ η (neⁿᶠ 𝒟)       = neⁿᶠ (mono⊢ⁿᵉ ζ η 𝒟)

  mono⊢ⁿᵉ :  {Δ Γ Δ′ Γ′ A}  Δ′  Δ  Γ′  Γ  Δ  Γ ⊢ⁿᵉ A  Δ′  Γ′ ⊢ⁿᵉ A
  mono⊢ⁿᵉ ζ η (varⁿᵉ 𝒾)      = varⁿᵉ (mono∋ η 𝒾)
  mono⊢ⁿᵉ ζ η (mvarⁿᵉ φ ψ 𝒾) = mvarⁿᵉ (mono⊢⧆ ζ done φ) (mono⊢⋆ ζ η ψ) (mono∋ ζ 𝒾)
  mono⊢ⁿᵉ ζ η (appⁿᵉ 𝒟 )    = appⁿᵉ (mono⊢ⁿᵉ ζ η 𝒟) (mono⊢ⁿᶠ ζ η )
  mono⊢ⁿᵉ ζ η (unboxⁿᵉ 𝒟 )  = unboxⁿᵉ (mono⊢ⁿᵉ ζ η 𝒟) (mono⊢ⁿᶠ (lift ζ) η )

mono⊢⋆ⁿᵉ :  {Δ Γ Δ′ Γ′ Ξ}  Δ′  Δ  Γ′  Γ  Δ  Γ ⊢⋆ⁿᵉ Ξ  Δ′  Γ′ ⊢⋆ⁿᵉ Ξ
mono⊢⋆ⁿᵉ ζ η ξ = mapAll (mono⊢ⁿᵉ ζ η) ξ

mutual
  idmono⊢ⁿᶠ :  {Δ Γ A}  (𝒟 : Δ  Γ ⊢ⁿᶠ A)  mono⊢ⁿᶠ refl⊇ refl⊇ 𝒟  𝒟
  idmono⊢ⁿᶠ (lamⁿᶠ 𝒟)      = cong lamⁿᶠ (idmono⊢ⁿᶠ 𝒟)
  idmono⊢ⁿᶠ (boxⁿᶠ 𝒟)      = refl
  idmono⊢ⁿᶠ (neⁿᶠ 𝒟)       = cong neⁿᶠ (idmono⊢ⁿᵉ 𝒟)

  idmono⊢ⁿᵉ :  {Δ Γ A}  (𝒟 : Δ  Γ ⊢ⁿᵉ A)  mono⊢ⁿᵉ refl⊇ refl⊇ 𝒟  𝒟
  idmono⊢ⁿᵉ (varⁿᵉ 𝒾)      = cong varⁿᵉ (idmono∋ 𝒾)
  idmono⊢ⁿᵉ (mvarⁿᵉ φ ψ 𝒾) = cong³ mvarⁿᵉ (idmono⊢⧆ φ) (idmono⊢⋆ ψ) (idmono∋ 𝒾)
  idmono⊢ⁿᵉ (appⁿᵉ 𝒟 )    = cong² appⁿᵉ (idmono⊢ⁿᵉ 𝒟) (idmono⊢ⁿᶠ )
  idmono⊢ⁿᵉ (unboxⁿᵉ 𝒟 )  = cong² unboxⁿᵉ (idmono⊢ⁿᵉ 𝒟) (idmono⊢ⁿᶠ )

mutual
  assocmono⊢ⁿᶠ :  {Δ Γ Δ′ Γ′ Γ″ Δ″ A} 
                    (ζ′ : Δ″  Δ′) (η′ : Γ″  Γ′) (ζ : Δ′  Δ) (η : Γ′  Γ) (𝒟 : Δ  Γ ⊢ⁿᶠ A) 
                    mono⊢ⁿᶠ ζ′ η′ (mono⊢ⁿᶠ ζ η 𝒟)  mono⊢ⁿᶠ (trans⊇ ζ′ ζ) (trans⊇ η′ η) 𝒟
  assocmono⊢ⁿᶠ ζ′ η′ ζ η (lamⁿᶠ 𝒟)      = cong lamⁿᶠ (assocmono⊢ⁿᶠ ζ′ (lift η′) ζ (lift η) 𝒟)
  assocmono⊢ⁿᶠ ζ′ η′ ζ η (boxⁿᶠ 𝒟)      = refl
  assocmono⊢ⁿᶠ ζ′ η′ ζ η (neⁿᶠ 𝒟)       = cong neⁿᶠ (assocmono⊢ⁿᵉ ζ′ η′ ζ η 𝒟)

  assocmono⊢ⁿᵉ :  {Δ Γ Δ′ Γ′ Γ″ Δ″ A} 
                    (ζ′ : Δ″  Δ′) (η′ : Γ″  Γ′) (ζ : Δ′  Δ) (η : Γ′  Γ) (𝒟 : Δ  Γ ⊢ⁿᵉ A) 
                    mono⊢ⁿᵉ ζ′ η′ (mono⊢ⁿᵉ ζ η 𝒟)  mono⊢ⁿᵉ (trans⊇ ζ′ ζ) (trans⊇ η′ η) 𝒟
  assocmono⊢ⁿᵉ ζ′ η′ ζ η (varⁿᵉ 𝒾)      = cong varⁿᵉ (assocmono∋ η′ η 𝒾)
  assocmono⊢ⁿᵉ ζ′ η′ ζ η (mvarⁿᵉ φ ψ 𝒾) = cong³ mvarⁿᵉ (assocmono⊢⧆ ζ′ done ζ done φ) (assocmono⊢⋆ ζ′ η′ ζ η ψ) (assocmono∋ ζ′ ζ 𝒾)
  assocmono⊢ⁿᵉ ζ′ η′ ζ η (appⁿᵉ 𝒟 )    = cong² appⁿᵉ (assocmono⊢ⁿᵉ ζ′ η′ ζ η 𝒟) (assocmono⊢ⁿᶠ ζ′ η′ ζ η )
  assocmono⊢ⁿᵉ ζ′ η′ ζ η (unboxⁿᵉ 𝒟 )  = cong² unboxⁿᵉ (assocmono⊢ⁿᵉ ζ′ η′ ζ η 𝒟) (assocmono⊢ⁿᶠ (lift ζ′) η′ (lift ζ) η )

idmono⊢⋆ⁿᵉ :  {Δ Γ Ξ}  (ξ : Δ  Γ ⊢⋆ⁿᵉ Ξ)  mono⊢⋆ⁿᵉ refl⊇ refl⊇ ξ  ξ
idmono⊢⋆ⁿᵉ        = refl
idmono⊢⋆ⁿᵉ (ξ , 𝒟) = cong² _,_ (idmono⊢⋆ⁿᵉ ξ) (idmono⊢ⁿᵉ 𝒟)

assocmono⊢⋆ⁿᵉ :  {Δ Γ Δ′ Γ′ Γ″ Δ″ Ξ} 
                   (ζ′ : Δ″  Δ′) (η′ : Γ″  Γ′) (ζ : Δ′  Δ) (η : Γ′  Γ) (ξ : Δ  Γ ⊢⋆ⁿᵉ Ξ) 
                   mono⊢⋆ⁿᵉ ζ′ η′ (mono⊢⋆ⁿᵉ ζ η ξ)  mono⊢⋆ⁿᵉ (trans⊇ ζ′ ζ) (trans⊇ η′ η) ξ
assocmono⊢⋆ⁿᵉ ζ′ η′ ζ η        = refl
assocmono⊢⋆ⁿᵉ ζ′ η′ ζ η (ξ , 𝒟) = cong² _,_ (assocmono⊢⋆ⁿᵉ ζ′ η′ ζ η ξ) (assocmono⊢ⁿᵉ ζ′ η′ ζ η 𝒟)


-- Example derivations.

v₀ :  {Δ Γ A} 
       Δ  Γ , A  A
v₀ = var zero

v₁ :  {Δ Γ A B} 
       Δ  Γ , A , B  A
v₁ = var (suc zero)

v₂ :  {Δ Γ A B C} 
       Δ  Γ , A , B , C  A
v₂ = var (suc (suc zero))

mv₀ :  {Δ Γ Φ Ψ A} 
        Δ , [ Φ  Ψ ] A   ⊢⧆ Φ 
        Δ , [ Φ  Ψ ] A  Γ ⊢⋆ Ψ 
        Δ , [ Φ  Ψ ] A  Γ  A
mv₀ φ ψ = mvar φ ψ zero

mv₁ :  {Δ Γ Φ Φ′ Ψ Ψ′ A B} 
        Δ , [ Φ  Ψ ] A , [ Φ′  Ψ′ ] B   ⊢⧆ Φ 
        Δ , [ Φ  Ψ ] A , [ Φ′  Ψ′ ] B  Γ ⊢⋆ Ψ 
        Δ , [ Φ  Ψ ] A , [ Φ′  Ψ′ ] B  Γ  A
mv₁ φ ψ = mvar φ ψ (suc zero)

mv₂ :  {Δ Γ Φ Φ′ Φ″ Ψ Ψ′ Ψ″ A B C} 
        Δ , [ Φ  Ψ ] A , [ Φ′  Ψ′ ] B , [ Φ″  Ψ″ ] C   ⊢⧆ Φ 
        Δ , [ Φ  Ψ ] A , [ Φ′  Ψ′ ] B , [ Φ″  Ψ″ ] C  Γ ⊢⋆ Ψ 
        Δ , [ Φ  Ψ ] A , [ Φ′  Ψ′ ] B , [ Φ″  Ψ″ ] C  Γ  A
mv₂ φ ψ = mvar φ ψ (suc (suc zero))

iᶜ :  {Δ Γ A} 
       Δ  Γ  A  A
iᶜ = lam v₀

kᶜ :  {Δ Γ A B} 
       Δ  Γ  A  B  A
kᶜ = lam (lam v₁)

sᶜ :  {Δ Γ A B C} 
       Δ  Γ  (A  B  C)  (A  B)  A  C
sᶜ = lam (lam (lam
       (app (app v₂ v₀) (app v₁ v₀))))

cᶜ :  {Δ Γ A B C} 
       Δ  Γ  (A  B  C)  B  A  C
cᶜ = lam (lam (lam
       (app (app v₂ v₀) v₁)))

bᶜ :  {Δ Γ A B C} 
       Δ  Γ  (B  C)  (A  B)  A  C
bᶜ = lam (lam (lam
       (app v₂ (app v₁ v₀))))

aᶜ :  {Δ Γ A B} 
       Δ  Γ  (A  A  B)  A  B
aᶜ = lam (lam
       (app (app v₁ v₀) v₀))

-- -- NOTE: Needs mrefl⊢⧆.
-- gendᶜ : ∀ {Δ Γ Φ Φ′ Ψ Ψ′ A B} →
--           Telescopic Δ →
--           Δ ⁏ Ψ ⊢⋆ Ψ′ →
--           Δ ⁏ Γ ⊢ [ Φ ⁏ Ψ′ ] (A ⇒ B) ⇒ [ Φ′ ⁏ Ψ′ ] A ⇒
--                    [ Δ , [ Δ ⁏ Ψ′ ] (A ⇒ B) , [ Δ ⁏ Ψ′ ] A ⁏ Ψ ] B
-- gendᶜ τ ψ = lam (lam (unbox v₁ (unbox v₀
--               (box (app (mv₁ (mono⊢⧆ (weak (weak refl⊇)) done (mrefl⊢⧆ τ))
--                              (mono⊢⋆ (weak (weak refl⊇)) refl⊇ ψ))
--                         (mv₀ (mono⊢⧆ (weak (weak refl⊇)) done (mrefl⊢⧆ τ))
--                              (mono⊢⋆ (weak (weak refl⊇)) refl⊇ ψ)))))))
--
-- gen4ᶜ : ∀ {Δ Γ Φ Φ′ Ψ Ψ′ Ψ″ A} →
--           Telescopic Δ →
--           Δ ⁏ Ψ ⊢⋆ Ψ′ →
--           Δ ⁏ Γ ⊢ [ Φ ⁏ Ψ′ ] A ⇒
--                    [ Φ′ ⁏ Ψ″ ] [ Δ , [ Δ ⁏ Ψ′ ] A ⁏ Ψ ] A
-- gen4ᶜ τ ψ = lam (unbox v₀
--               (box (box (mv₀ (mono⊢⧆ (weak refl⊇) refl⊇ (mrefl⊢⧆ τ))
--                              (mono⊢⋆ (weak refl⊇) refl⊇ ψ)))))
--
-- gentᶜ : ∀ {Δ Γ Ψ A} →
--           Telescopic Δ →
--           Δ ⁏ Γ ⊢⋆ Ψ →
--           Δ ⁏ Γ ⊢ [ Δ ⁏ Ψ ] A ⇒ A
-- gentᶜ τ ψ = lam (unbox v₀
--               (mv₀ (mono⊢⧆ (weak refl⊇) refl⊇ (mrefl⊢⧆ τ))
--                    (mono⊢⋆ (weak refl⊇) (weak refl⊇) ψ)))
--
-- dᶜ : ∀ {Δ Γ Φ Φ′ A B} →
--        Telescopic Δ →
--        Δ ⁏ Γ ⊢ [ Φ ⁏ ∅ ] (A ⇒ B) ⇒ [ Φ′ ⁏ ∅ ] A ⇒
--                 [ Δ , [ Δ ⁏ ∅ ] (A ⇒ B) , [ Δ ⁏ ∅ ] A ⁏ ∅ ] B
-- dᶜ τ = gendᶜ τ ∅
--
-- 4ᶜ : ∀ {Δ Γ Φ Φ′ A} →
--        Telescopic Δ →
--        Δ ⁏ Γ ⊢ [ Φ ⁏ ∅ ] A ⇒
--                 [ Φ′ ⁏ ∅ ] [ Δ , [ Δ ⁏ ∅ ] A ⁏ ∅ ] A
-- 4ᶜ τ = gen4ᶜ τ ∅
--
-- tᶜ : ∀ {Δ Γ A} →
--        Telescopic Δ →
--        Δ ⁏ Γ ⊢ [ Δ ⁏ ∅ ] A ⇒ A
-- tᶜ τ = gentᶜ τ ∅


-- Example inference rules on derivations.

exch :  {Δ Γ A B C} 
         Δ  Γ  A  B  C 
         Δ  Γ  B  A  C
exch 𝒟 = app cᶜ 𝒟

comp :  {Δ Γ A B C} 
         Δ  Γ  B  C  Δ  Γ  A  B 
         Δ  Γ  A  C
comp 𝒟  = app (app bᶜ 𝒟) 

cont :  {Δ Γ A B} 
         Δ  Γ  A  A  B 
         Δ  Γ  A  B
cont 𝒟 = app aᶜ 𝒟

det :  {Δ Γ A B} 
        Δ  Γ  A  B 
        Δ  Γ , A  B
det 𝒟 = app (mono⊢ refl⊇ (weak refl⊇) 𝒟) v₀

-- -- TODO: What is going on here?
-- -- Goal:     Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ [ Φ ⁏ Ψ ] A
-- -- Have:     Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ [ Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ] A
-- -- Subgoal₁: Δ , [ Φ ⁏ Ψ ] A ⁏ ∅ ⊢⧆ Φ
-- -- Subgoal₂: Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢⋆ Ψ
-- mdet : ∀ {Δ Γ Φ Ψ A B} →
--          Δ ⁏ Γ ⊢ [ Φ ⁏ Ψ ] A ⇒ B →
--          Δ , [ Φ ⁏ Ψ ] A ⁏ Γ ⊢ B
-- mdet {Δ} {Γ} {Φ} {Ψ} {A} {B} 𝒟 =
--   app (mono⊢ (weak refl⊇) refl⊇ 𝒟)
--       (oops (box {Δ , [ Φ ⁏ Ψ ] A} {Γ} (mv₀ {Δ} {Γ} {Φ} {Ψ} {A} {!!} {!!})))
--
-- -- NOTE: Needs example derivations.
-- dist : ∀ {Δ Γ Φ Φ′ A B} →
--          Telescopic Δ →
--          Δ ⁏ Γ ⊢ [ Φ ⁏ ∅ ] (A ⇒ B) → Δ ⁏ Γ ⊢ [ Φ′ ⁏ ∅ ] A →
--          Δ ⁏ Γ ⊢ [ Δ , [ Δ ⁏ ∅ ] (A ⇒ B) , [ Δ ⁏ ∅ ] A ⁏ ∅ ] B
-- dist τ 𝒟 ℰ = app (app (dᶜ τ) 𝒟) ℰ
--
-- wrap : ∀ {Δ Γ Φ Φ′ A} →
--          Telescopic Δ →
--          Δ ⁏ Γ ⊢ [ Φ ⁏ ∅ ] A →
--          Δ ⁏ Γ ⊢ [ Φ′ ⁏ ∅ ] [ Δ , [ Δ ⁏ ∅ ] A ⁏ ∅ ] A
-- wrap τ 𝒟 = app (4ᶜ τ) 𝒟
--
-- eval : ∀ {Δ Γ A} →
--          Telescopic Δ →
--          Δ ⁏ Γ ⊢ [ Δ ⁏ ∅ ] A →
--          Δ ⁏ Γ ⊢ A
-- eval τ 𝒟 = app (tᶜ τ) 𝒟