{-# OPTIONS --without-K  #-}
open import Data.Nat using (; zero; suc; _+_)
open import Data.Nat.Properties using (+-comm; +-assoc)
open import Structures
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; cong; cong₂; cong-app)
open import Var

module GSubst where

GSubst : ∀{} (V : Set )  Set 
GSubst V = Var  V

 : (k : )  ∀{}{V : Set }{{_ : Shiftable V}}  GSubst {} V
 k x = var→val (k + x)

infixr 6 _•_
_•_ : ∀{}{V : Set }  V  GSubst V  GSubst V
(v  σ) 0 = v
(v  σ) (suc x) = σ x

 : ∀{}{V : Set } {{_ : Shiftable V}}  GSubst V  GSubst V
 σ x =  (σ x)

id :  {}{V : Set }{{_ : Shiftable V}}  GSubst V
id =  0

ext : ∀{}{V : Set } {{_ : Shiftable V}}  GSubst V  GSubst V
ext σ = (var→val 0)   σ

{- obsolete, use (v • ⟰ σ) instead of (σ , v) -}
{-
_,_ : ∀{ℓ}{V : Set ℓ} {{_ : Shiftable V}} → GSubst V → V → GSubst V
(σ , v) = v • ⟰ σ
-}

drop : ∀{}{V : Set }  (k : )  GSubst V  GSubst V
drop k σ x = σ (k + x)

map-sub : ∀{}{V W : Set }  (V  W)  GSubst V  GSubst W
map-sub f σ x = f (σ x)

map-sub-id : ∀{}{V : Set } (σ : GSubst V)  map-sub  x  x) σ  σ
map-sub-id σ = refl

map-sub-drop : ∀{} {V W : Set } σ f k
    map-sub {}{V}{W} f (drop k σ)  drop k (map-sub f σ)
map-sub-drop σ f k = refl

drop-0 :  {}{V : Set } σ  drop {}{V} 0 σ  σ
drop-0 σ = refl

drop-drop :  {}{V} k k' σ  drop {} {V} (k + k') σ  drop k (drop k' σ)
drop-drop k k' σ = extensionality G
  where
  G : (x : Var)  drop (k + k') σ x  drop k (drop k' σ) x
  G x rewrite +-comm k k' | +-assoc k' k x = refl
  
shifts : ∀{}{V : Set } {{_ : Shiftable V}}    V  V
shifts zero v = v
shifts (suc k) v =  (shifts k v) 

drop-inc : ∀{}{V : Set } {{_ : Shiftable V}}
    (k : ) (σ : GSubst V)  drop k ( σ)   (drop k σ)
drop-inc k σ = refl

Z-shift : ∀{}{V : Set } {{_ : Shiftable V}}
    (x : Var)  (var→val{}{V} 0   1) x  var→val{}{V} x
Z-shift 0 = refl
Z-shift (suc x) = refl

ext-cong : ∀{}{V : Set } {{_ : Shiftable V}} {σ₁ σ₂ : GSubst V}
   ((x : )  σ₁ x  σ₂ x)
   (x : )  ext σ₁ x  ext σ₂ x
ext-cong {σ₁ = σ₁} {σ₂} f zero = refl
ext-cong {σ₁ = σ₁} {σ₂} f (suc x) rewrite f x = refl

drop-ext : ∀{}{V : Set } {{_ : Shiftable V}}
    (k : Var) (σ : GSubst V)
    drop (suc k) (ext σ)   (drop k σ)
drop-ext k σ = refl

Shift : ∀{}{V : Set } {{_ : Shiftable V}}    GSubst V  Set 
Shift k σ =  x  σ x  shifts k (var→val x)

inc-Shift : ∀{}{V : Set } {{_ : Shiftable V}} {k}{σ : GSubst V}
    Shift k σ  Shift (suc k) ( σ)
inc-Shift {} {V} {k} {σ} shk x rewrite shk x = refl

shifts-var→val : ∀{}{V : Set } {{S : Shiftable V}}
    (k x : )  shifts k (var→val{}{V} x)  var→val (k + x)
shifts-var→val zero x = refl
shifts-var→val{}{V}{{S}} (suc k) x rewrite shifts-var→val{}{V} k x
    | var→val-suc-shift {{S}} {x = k + x} = refl

Shift-var : ∀{}{V : Set } {{_ : Shiftable V}}
    (σ : GSubst V) (k : )
    (x : Var)  Shift{}{V} k σ  σ x  var→val (k + x)
Shift-var σ zero x sft rewrite sft x = refl
Shift-var {{S}} σ (suc k) x sft rewrite sft x
    | var→val-suc-shift {{S}} {x = k + x}
    | shifts-var→val {{S}} k x = refl

up-seq : ∀{}{V₁ V₂ V₃ : Set }{{S : Shiftable V₁}}
   {{C : Composable V₁ V₂ V₃}}
   k (σ₂ : GSubst V₂)
     k  σ₂  map-sub val₂₃ (drop k σ₂)
up-seq {{S}}{{C}} k σ₂ = extensionality G
    where
    G : (x : Var)  ( k  σ₂) x  map-sub (Composable.val₂₃ C) (drop k σ₂) x
    G x rewrite ⌈⌉-var→val σ₂ (k + x) = refl

cons-seq : ∀{}{V₁ V₂ V₃ : Set } {{_ : Shiftable V₁}} {{_ : Shiftable V₃}}
   {{C : Composable V₁ V₂ V₃}}
   v₁ (σ₁ : GSubst V₁) (σ₂ : GSubst V₂)
    (v₁  σ₁)  σ₂   σ₂  v₁  (σ₁  σ₂)
cons-seq {{C = C}} v₁ σ₁ σ₂ = extensionality G
   where
   G :   (x : Var)  (v₁  σ₁  σ₂) x  (Composable.⌈ C  σ₂ v₁  (σ₁  σ₂)) x
   G zero = refl
   G (suc x) = refl