module A201605.AltArtemov.Old.G.Vec.Prov where

open import A201605.AltArtemov.Old.G.Vec.True renaming (ᵗ⌊_⌋ to ᵗ⌊_⌋ᵀ) public


data Prov (Γ : Cx) : ∀ {n} → Vec ᵍ⌊ Γ ⌋ n → Ty → Set where
  var[_]  : ∀ n {A} (x : Var Γ A) →
              Prov Γ (VARs[ n ] ⁱ⌊ x ⌋) A
  lam[_]  : ∀ n {ts : Vec (suc ᵍ⌊ Γ ⌋) n} {A B} → Prov (Γ , A) ts B →
              Prov Γ (LAMs[ n ] ts) (A ⊃ B)
  app[_]  : ∀ n {ts us : Vec ᵍ⌊ Γ ⌋ n} {A B} → Prov Γ ts (A ⊃ B) → Prov Γ us A →
              Prov Γ (APPs[ n ] ts us) B
  pair[_] : ∀ n {ts us : Vec ᵍ⌊ Γ ⌋ n} {A B} → Prov Γ ts A → Prov Γ us B →
              Prov Γ (PAIRs[ n ] ts us) (A ∧ B)
  fst[_]  : ∀ n {ts : Vec ᵍ⌊ Γ ⌋ n} {A B} → Prov Γ ts (A ∧ B) →
              Prov Γ (FSTs[ n ] ts) A
  snd[_]  : ∀ n {ts : Vec ᵍ⌊ Γ ⌋ n} {A B} → Prov Γ ts (A ∧ B) →
              Prov Γ (SNDs[ n ] ts) B
  up[_]   : ∀ n {ts : Vec ᵍ⌊ Γ ⌋ n} {u A} → Prov Γ ts (u ∶ A) →
              Prov Γ (UPs[ n ] ts) (! u ∶ u ∶ A)
  down[_] : ∀ n {ts : Vec ᵍ⌊ Γ ⌋ n} {u A} → Prov Γ ts (u ∶ A) →
              Prov Γ (DOWNs[ n ] ts) A

ᵗ⌊_⌋ : ∀ {Γ n A} {ts : Vec ᵍ⌊ Γ ⌋ n} → Prov Γ ts A → Tm ᵍ⌊ Γ ⌋
ᵗ⌊ var[ n ] x ⌋      = VAR[ n ] ⁱ⌊ x ⌋
ᵗ⌊ lam[ n ] j ⌋      = LAM[ n ] ᵗ⌊ j ⌋
ᵗ⌊ app[ n ] j₁ j₂ ⌋  = APP[ n ] ᵗ⌊ j₁ ⌋ ᵗ⌊ j₂ ⌋
ᵗ⌊ pair[ n ] j₁ j₂ ⌋ = PAIR[ n ] ᵗ⌊ j₁ ⌋ ᵗ⌊ j₂ ⌋
ᵗ⌊ fst[ n ] j ⌋      = FST[ n ] ᵗ⌊ j ⌋
ᵗ⌊ snd[ n ] j ⌋      = SND[ n ] ᵗ⌊ j ⌋
ᵗ⌊ up[ n ] j ⌋       = UP[ n ] ᵗ⌊ j ⌋
ᵗ⌊ down[ n ] j ⌋     = DOWN[ n ] ᵗ⌊ j ⌋

true⇒ : ∀ {Γ A} → True Γ A → Prov Γ [] A
true⇒ (var x)      = var[ 0 ] x
true⇒ (lam j)      = lam[ 0 ] (true⇒ j)
true⇒ (app j₁ j₂)  = app[ 0 ] (true⇒ j₁) (true⇒ j₂)
true⇒ (pair j₁ j₂) = pair[ 0 ] (true⇒ j₁) (true⇒ j₂)
true⇒ (fst j)      = fst[ 0 ] (true⇒ j)
true⇒ (snd j)      = snd[ 0 ] (true⇒ j)
true⇒ (up j)       = up[ 0 ] (true⇒ j)
true⇒ (down j)     = down[ 0 ] (true⇒ j)

true⇐ : ∀ {Γ A} {ts : Vec ᵍ⌊ Γ ⌋ 0} → Prov Γ ts A → True Γ A
true⇐ (var[ .0 ] x)      = var x
true⇐ (lam[ .0 ] j)      = lam (true⇐ j)
true⇐ (app[ .0 ] j₁ j₂)  = app (true⇐ j₁) (true⇐ j₂)
true⇐ (pair[ .0 ] j₁ j₂) = pair (true⇐ j₁) (true⇐ j₂)
true⇐ (fst[ .0 ] j)      = fst (true⇐ j)
true⇐ (snd[ .0 ] j)      = snd (true⇐ j)
true⇐ (up[ .0 ] j)       = up (true⇐ j)
true⇐ (down[ .0 ] j)     = down (true⇐ j)

true⇒⇐-id : ∀ {Γ A} (j : True Γ A) → true⇐ (true⇒ j) ≡ j
true⇒⇐-id (var x)      = refl
true⇒⇐-id (lam j)      = cong lam (true⇒⇐-id j)
true⇒⇐-id (app j₁ j₂)  = cong₂ app (true⇒⇐-id j₁) (true⇒⇐-id j₂)
true⇒⇐-id (pair j₁ j₂) = cong₂ pair (true⇒⇐-id j₁) (true⇒⇐-id j₂)
true⇒⇐-id (fst j)      = cong fst (true⇒⇐-id j)
true⇒⇐-id (snd j)      = cong snd (true⇒⇐-id j)
true⇒⇐-id (up j)       = cong up (true⇒⇐-id j)
true⇒⇐-id (down j)     = cong down (true⇒⇐-id j)

true⇗ : ∀ {Γ A} (j : True Γ A) → Prov Γ [ ᵗ⌊ j ⌋ᵀ ] A
true⇗ (var x)      = var[ 1 ] x
true⇗ (lam j)      = lam[ 1 ] (true⇗ j)
true⇗ (app j₁ j₂)  = app[ 1 ] (true⇗ j₁) (true⇗ j₂)
true⇗ (pair j₁ j₂) = pair[ 1 ] (true⇗ j₁) (true⇗ j₂)
true⇗ (fst j)      = fst[ 1 ] (true⇗ j)
true⇗ (snd j)      = snd[ 1 ] (true⇗ j)
true⇗ (up j)       = up[ 1 ] (true⇗ j)
true⇗ (down j)     = down[ 1 ] (true⇗ j)

true⇙ : ∀ {Γ n A} {ts : Vec ᵍ⌊ Γ ⌋ n} → Prov Γ ts A → True Γ A
true⇙ (var[ n ] x)      = var x
true⇙ (lam[ n ] j)      = lam (true⇙ j)
true⇙ (app[ n ] j₁ j₂)  = app (true⇙ j₁) (true⇙ j₂)
true⇙ (pair[ n ] j₁ j₂) = pair (true⇙ j₁) (true⇙ j₂)
true⇙ (fst[ n ] j)      = fst (true⇙ j)
true⇙ (snd[ n ] j)      = snd (true⇙ j)
true⇙ (up[ n ] j)       = up (true⇙ j)
true⇙ (down[ n ] j)     = down (true⇙ j)

true⇗⇙-id : ∀ {Γ A} (j : True Γ A) → true⇙ (true⇗ j) ≡ j
true⇗⇙-id (var x)      = refl
true⇗⇙-id (lam j)      = cong lam (true⇗⇙-id j)
true⇗⇙-id (app j₁ j₂)  = cong₂ app (true⇗⇙-id j₁) (true⇗⇙-id j₂)
true⇗⇙-id (pair j₁ j₂) = cong₂ pair (true⇗⇙-id j₁) (true⇗⇙-id j₂)
true⇗⇙-id (fst j)      = cong fst (true⇗⇙-id j)
true⇗⇙-id (snd j)      = cong snd (true⇗⇙-id j)
true⇗⇙-id (up j)       = cong up (true⇗⇙-id j)
true⇗⇙-id (down j)     = cong down (true⇗⇙-id j)

prov⇗ : ∀ {Γ n A} {ts : Vec ᵍ⌊ Γ ⌋ n} (j : Prov Γ ts A) →
          Prov Γ (ᵗ⌊ j ⌋ ∷ ts) A
prov⇗ (var[ n ] x)      = var[ suc n ] x
prov⇗ (lam[ n ] j)      = lam[ suc n ] (prov⇗ j)
prov⇗ (app[ n ] j₁ j₂)  = app[ suc n ] (prov⇗ j₁) (prov⇗ j₂)
prov⇗ (pair[ n ] j₁ j₂) = pair[ suc n ] (prov⇗ j₁) (prov⇗ j₂)
prov⇗ (fst[ n ] j)      = fst[ suc n ] (prov⇗ j)
prov⇗ (snd[ n ] j)      = snd[ suc n ] (prov⇗ j)
prov⇗ (up[ n ] j)       = up[ suc n ] (prov⇗ j)
prov⇗ (down[ n ] j)     = down[ suc n ] (prov⇗ j)

prov⇙ : ∀ {n Γ A} {ts : Vec ᵍ⌊ Γ ⌋ (suc n)} (j : Prov Γ ts A) →
          Prov Γ (tail ts) A
prov⇙ {n} (var[ .(suc n) ] x)                = var[ n ] x
prov⇙ {n} (lam[ .(suc n) ] {ts} j)           rewrite tail-LAMs ts =
                                                lam[ n ] (prov⇙ j)
prov⇙ {n} (app[ .(suc n) ] {ts} {us} j₁ j₂)  rewrite tail-APPs ts us =
                                                app[ n ] (prov⇙ j₁) (prov⇙ j₂)
prov⇙ {n} (pair[ .(suc n) ] {ts} {us} j₁ j₂) rewrite tail-PAIRs ts us =
                                                pair[ n ] (prov⇙ j₁) (prov⇙ j₂)
prov⇙ {n} (fst[ .(suc n) ] {ts} j)           rewrite tail-FSTs ts =
                                                fst[ n ] (prov⇙ j)
prov⇙ {n} (snd[ .(suc n) ] {ts} j)           rewrite tail-SNDs ts =
                                                snd[ n ] (prov⇙ j)
prov⇙ {n} (up[ .(suc n) ] {ts} j)            rewrite tail-UPs ts =
                                                up[ n ] (prov⇙ j)
prov⇙ {n} (down[ .(suc n) ] {ts} j)          rewrite tail-DOWNs ts =
                                                down[ n ] (prov⇙ j)

prov⇗⇙-id : ∀ {Γ n A} {ts : Vec ᵍ⌊ Γ ⌋ n} (j : Prov Γ ts A) →
              prov⇙ (prov⇗ j) ≡ j
prov⇗⇙-id (var[ n ] x)      = refl
prov⇗⇙-id (lam[ n ] j)      = cong lam[ n ] (prov⇗⇙-id j)
prov⇗⇙-id (app[ n ] j₁ j₂)  = cong₂ app[ n ] (prov⇗⇙-id j₁) (prov⇗⇙-id j₂)
prov⇗⇙-id (pair[ n ] j₁ j₂) = cong₂ pair[ n ] (prov⇗⇙-id j₁) (prov⇗⇙-id j₂)
prov⇗⇙-id (fst[ n ] j)      = cong fst[ n ] (prov⇗⇙-id j)
prov⇗⇙-id (snd[ n ] j)      = cong snd[ n ] (prov⇗⇙-id j)
prov⇗⇙-id (up[ n ] j)       = cong up[ n ] (prov⇗⇙-id j)
prov⇗⇙-id (down[ n ] j)     = cong down[ n ] (prov⇗⇙-id j)

ren-prov : ∀ {Γ Γ′ n A} {ts : Vec ᵍ⌊ Γ ⌋ n} (η : Γ′ ⊇ Γ) → Prov Γ ts A →
             Prov Γ′ (ren-vec ʰ⌊ η ⌋ ts) A
ren-prov η (var[ n ] x)                rewrite ren-VARs {n} ʰ⌊ η ⌋ ⁱ⌊ x ⌋ |
                                               ren-fin-⌊⌋-var η x =
                                         var[ n ] (ren-var η x)
ren-prov η (lam[ n ] {ts} j)           rewrite ren-LAMs ʰ⌊ η ⌋ ts =
                                         lam[ n ] (ren-prov (lift η) j)
ren-prov η (app[ n ] {ts} {us} j₁ j₂)  rewrite ren-APPs ʰ⌊ η ⌋ ts us =
                                         app[ n ] (ren-prov η j₁) (ren-prov η j₂)
ren-prov η (pair[ n ] {ts} {us} j₁ j₂) rewrite ren-PAIRs ʰ⌊ η ⌋ ts us =
                                         pair[ n ] (ren-prov η j₁) (ren-prov η j₂)
ren-prov η (fst[ n ] {ts} j)           rewrite ren-FSTs ʰ⌊ η ⌋ ts =
                                         fst[ n ] (ren-prov η j)
ren-prov η (snd[ n ] {ts} j)           rewrite ren-SNDs ʰ⌊ η ⌋ ts =
                                         snd[ n ] (ren-prov η j)
ren-prov η (up[ n ] {ts} j)            rewrite ren-UPs ʰ⌊ η ⌋ ts =
                                         up[ n ] (ren-prov η j)
ren-prov η (down[ n ] {ts} j)          rewrite ren-DOWNs ʰ⌊ η ⌋ ts =
                                         down[ n ] (ren-prov η j)

wk-prov : ∀ {Γ n A C} {ts : Vec ᵍ⌊ Γ ⌋ n} → Prov Γ ts C →
              Prov (Γ , A) (wk-vec ts) C
wk-prov {Γ} rewrite sym (id-⌊⌋-id Γ) = ren-prov ⊇wk

wk*-prov : ∀ {Γ n C} {ts : Vec 0 n} → Prov ∅ ts C →
               Prov Γ (wk*-vec ts) C
wk*-prov {Γ} rewrite sym (to-⌊⌋-to Γ) = ren-prov ⊇to

v₀[_] : ∀ {Γ} n {A} → Prov (Γ , A) (VARs[ n ] i₀) A
v₀[ n ] = var[ n ] x₀

v₁[_] : ∀ {Γ} n {A B} → Prov ((Γ , A) , B) (VARs[ n ] i₁) A
v₁[ n ] = var[ n ] x₁

v₂[_] : ∀ {Γ} n {A B C} → Prov (((Γ , A) , B) , C) (VARs[ n ] i₂) A
v₂[ n ] = var[ n ] x₂

I[_] : ∀ {Γ} n {A} → Prov Γ (LAMs[ n ] (VARs[ n ] i₀)) (A ⊃ A)
I[ n ] = lam[ n ] v₀[ n ]

K[_] : ∀ {Γ} n {A B} → Prov Γ (LAMs[ n ] (LAMs[ n ] (VARs[ n ] i₁))) (A ⊃ B ⊃ A)
K[ n ] = lam[ n ] (lam[ n ] v₁[ n ])

S[_] : ∀ {Γ} n {A B C} →
         Prov Γ (LAMs[ n ] (LAMs[ n ] (LAMs[ n ]
                    (APPs[ n ] (APPs[ n ] (VARs[ n ] i₂) (VARs[ n ] i₀))
                               (APPs[ n ] (VARs[ n ] i₁) (VARs[ n ] i₀))))))
                ((A ⊃ B ⊃ C) ⊃ (A ⊃ B) ⊃ A ⊃ C)
S[ n ] = lam[ n ] (lam[ n ] (lam[ n ]
           (app[ n ] (app[ n ] v₂[ n ] v₀[ n ])
                     (app[ n ] v₁[ n ] v₀[ n ]))))

I≡I[0] : ∀ {Γ A} → true⇒ (I {Γ} {A}) ≡ I[ 0 ]
I≡I[0] = refl

⇗I≡I[1] : ∀ {Γ A} → true⇗ (I {Γ} {A}) ≡ I[ 1 ]
⇗I≡I[1] = refl

⇗⇗I≡I[2] : ∀ {Γ A} → prov⇗ (true⇗ (I {Γ} {A})) ≡ I[ 2 ]
⇗⇗I≡I[2] = refl