module A201706.IPCSyntaxNoTerms where

open import A201706.IPC public
open IPCList public


-- Contexts.

Cx : Set
Cx = Ty⋆


-- Derivations.

infix 3 _⊢_
data _⊢_ : Cx  Ty  Set where
  var :  {Γ A} 
          Γ  A 
          Γ  A
  lam :  {Γ A B} 
          Γ , A  B 
          Γ  A  B
  app :  {Γ A B} 
          Γ  A  B  Γ  A 
          Γ  B

mono⊢ :  {Γ Γ′ A}  Γ′  Γ  Γ  A  Γ′  A
mono⊢ η (var 𝒾)   = var (mono∋ η 𝒾)
mono⊢ η (lam 𝒟)   = lam (mono⊢ (lift η) 𝒟)
mono⊢ η (app 𝒟 ) = app (mono⊢ η 𝒟) (mono⊢ η )

idmono⊢ :  {Γ A}  (𝒟 : Γ  A)  mono⊢ refl⊇ 𝒟  𝒟
idmono⊢ (var 𝒾)   = cong var (idmono∋ 𝒾)
idmono⊢ (lam 𝒟)   = cong lam (idmono⊢ 𝒟)
idmono⊢ (app 𝒟 ) = cong² app (idmono⊢ 𝒟) (idmono⊢ )

assocmono⊢ :  {Γ Γ′ Γ″ A}  (η′ : Γ″  Γ′) (η : Γ′  Γ) (𝒟 : Γ  A) 
                mono⊢ η′ (mono⊢ η 𝒟)  mono⊢ (trans⊇ η′ η) 𝒟
assocmono⊢ η′ η (var 𝒾)   = cong var (assocmono∋ η′ η 𝒾)
assocmono⊢ η′ η (lam 𝒟)   = cong lam (assocmono⊢ (lift η′) (lift η) 𝒟)
assocmono⊢ η′ η (app 𝒟 ) = cong² app (assocmono⊢ η′ η 𝒟) (assocmono⊢ η′ η )


-- Lists of derivations.

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

mono⊢⋆ :  {Γ Γ′ Ξ}  Γ′  Γ  Γ ⊢⋆ Ξ  Γ′ ⊢⋆ Ξ
mono⊢⋆ η ξ = mapAll (mono⊢ η) ξ

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

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

graft⊢ :  {Γ Φ A}  Γ ⊢⋆ Φ  Φ  A  Γ  A
graft⊢ φ (var 𝒾)   = lookup⊢ φ 𝒾
graft⊢ φ (lam 𝒟)   = lam (graft⊢ (mono⊢⋆ (weak refl⊇) φ , var zero) 𝒟)
graft⊢ φ (app 𝒟 ) = app (graft⊢ φ 𝒟) (graft⊢ φ )

graft⊢⋆ :  {Γ Φ Ξ}  Γ ⊢⋆ Φ  Φ ⊢⋆ Ξ  Γ ⊢⋆ Ξ
graft⊢⋆ φ ξ = mapAll (graft⊢ φ) ξ

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


-- Normal forms.

mutual
  infix 3 _⊢ⁿᶠ_
  data _⊢ⁿᶠ_ : Cx  Ty  Set where
    lamⁿᶠ :  {Γ A B} 
              Γ , A ⊢ⁿᶠ B 
              Γ ⊢ⁿᶠ A  B
    neⁿᶠ  :  {Γ A} 
              Γ ⊢ⁿᵉ A 
              Γ ⊢ⁿᶠ A

  infix 3 _⊢ⁿᵉ_
  data _⊢ⁿᵉ_ : Cx  Ty  Set where
    varⁿᵉ :  {Γ A} 
              Γ  A 
              Γ ⊢ⁿᵉ A
    appⁿᵉ :  {Γ A B} 
              Γ ⊢ⁿᵉ A  B  Γ ⊢ⁿᶠ A 
              Γ ⊢ⁿᵉ B

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

  mono⊢ⁿᵉ :  {Γ Γ′ A}  Γ′  Γ  Γ ⊢ⁿᵉ A  Γ′ ⊢ⁿᵉ A
  mono⊢ⁿᵉ η (varⁿᵉ 𝒾)   = varⁿᵉ (mono∋ η 𝒾)
  mono⊢ⁿᵉ η (appⁿᵉ 𝒟 ) = appⁿᵉ (mono⊢ⁿᵉ η 𝒟) (mono⊢ⁿᶠ η )

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

  idmono⊢ⁿᵉ :  {Γ A}  (𝒟 : Γ ⊢ⁿᵉ A)  mono⊢ⁿᵉ refl⊇ 𝒟  𝒟
  idmono⊢ⁿᵉ (varⁿᵉ 𝒾)   = cong varⁿᵉ (idmono∋ 𝒾)
  idmono⊢ⁿᵉ (appⁿᵉ 𝒟 ) = cong² appⁿᵉ (idmono⊢ⁿᵉ 𝒟) (idmono⊢ⁿᶠ )

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

  assocmono⊢ⁿᵉ :  {Γ Γ′ Γ″ A}  (η′ : Γ″  Γ′) (η : Γ′  Γ) (𝒟 : Γ ⊢ⁿᵉ A)  
                    mono⊢ⁿᵉ η′ (mono⊢ⁿᵉ η 𝒟)  mono⊢ⁿᵉ (trans⊇ η′ η) 𝒟
  assocmono⊢ⁿᵉ η′ η (varⁿᵉ 𝒾)   = cong varⁿᵉ (assocmono∋ η′ η 𝒾)
  assocmono⊢ⁿᵉ η′ η (appⁿᵉ 𝒟 ) = cong² appⁿᵉ (assocmono⊢ⁿᵉ η′ η 𝒟) (assocmono⊢ⁿᶠ η′ η )


-- Lists of normal forms.

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

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


-- 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))

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₀))


-- 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⊢ (weak refl⊇) 𝒟) v₀