module stlc.properities where

open import stlc.term

_+++_ : Context  Context  Context
Γ +++  = Γ
Γ +++ (Δ , A) = (Γ +++ Δ) , A

weaken∋ :  {Γ Γ' A B}  Γ +++ Γ'  B  (Γ , A) +++ Γ'  B
weaken∋ {Γ' = } Z = S Z
weaken∋ {Γ' = } (S x) = S (S x)
weaken∋ {Γ' = Γ' , x₁} Z = Z
weaken∋ {Γ' = Γ' , x₁} (S x) = S weaken∋ x

weaken :  {Γ Γ' A B}  Γ +++ Γ'  B  (Γ , A) +++ Γ'  B
weaken ⟨⟩ = ⟨⟩
weaken (` x) = ` (weaken∋ x)
weaken (x , x₁) = weaken x , weaken x₁
weaken (fst x) = fst (weaken x)
weaken (snd x) = snd (weaken x)
weaken {Γ' = Γ'} (ƛ_ {A = A} x) = ƛ weaken {Γ' = Γ' , A} x
weaken (x · x₁) = weaken x · weaken x₁
weaken (`nat x) = `nat x
weaken (inl x) = inl weaken x
weaken (inr x) = inr weaken x
weaken {Γ' = Γ'} (case_inl_inr_ {A = A} {B} x x₁ x₂) = case weaken x inl weaken {Γ' = Γ' , A} x₁ inr weaken {Γ' = Γ' , B} x₂
weaken [] = []
weaken (h  t) = weaken h  weaken t
weaken {Γ} (it x r l) = it (weaken x) (weaken {Γ} r) (weaken l)
weaken {Γ} (`let_`in_ {s = s} x x₁) = `let_`in_ {s = s} (weaken x) (weaken {Γ} x₁)
weaken (return {m = m} x) = return {m = m} (weaken x)

exchange∋ :  {Γ Γ' A B C}  (Γ , A , B) +++ Γ'  C  (Γ , B , A) +++ Γ'  C
exchange∋ {Γ' = } Z = S Z
exchange∋ {Γ} {Γ' = } (S x) = weaken∋ {Γ} x
exchange∋ {Γ' = Γ' , x₁} Z = Z
exchange∋ {Γ' = Γ' , x₁} (S x) = S exchange∋ x

exchange :  {Γ Γ' A B C}  (Γ , A , B) +++ Γ'  C  (Γ , B , A) +++ Γ'  C
exchange ⟨⟩ = ⟨⟩
exchange (` x) = ` (exchange∋ x)
exchange (x , x₁) = exchange x , exchange x₁
exchange (fst x) = fst (exchange x)
exchange (snd x) = snd (exchange x)
exchange {Γ' = Γ'} (ƛ_ {A = A} x) = ƛ exchange {Γ' = Γ' , A} x
exchange (x · x₁) = exchange x · exchange x₁
exchange (`nat x) = `nat x
exchange (inl x) = inl exchange x
exchange (inr x) = inr exchange x
exchange {Γ' = Γ'} (case_inl_inr_ {A = A} {B} x x₁ x₂) = case exchange x inl exchange {Γ' = Γ' , A} x₁ inr exchange {Γ' = Γ' , B} x₂
exchange [] = []
exchange (h  t) = exchange h  exchange t
exchange {Γ' = Γ'} {C = C} (it {A = A} x r l) = it (exchange x) (exchange {Γ' = Γ' , (A × C)} r) (exchange l)
exchange {Γ} {Γ'} (`let_`in_ {A = A} {s = s} x x₁) = `let_`in_ {s = s} (exchange x) (exchange {Γ' = Γ' , A} x₁)
exchange (return {m = m} x) = return {m = m} (exchange x)