module linear.Scope where

open import Data.Nat
open import Data.Fin hiding (_+_)
open import Function

data Mergey : (k l : ℕ) → Set where
  finish : {k : ℕ} → Mergey k k
  copy   : {k l : ℕ} → Mergey k l → Mergey (suc k) (suc l)
  insert : {k l : ℕ} → Mergey k l → Mergey k (suc l)

Weakening : (T : ℕ → Set) → Set
Weakening T = {k l : ℕ} (m : Mergey k l) → T k → T l

Extending : (T : ℕ → ℕ → Set) → Set
Extending T = {k l : ℕ} (o : ℕ) → T k l → T (o + k) (o + l)

copys : Extending Mergey
copys zero    m = m
copys (suc o) m = copy (copys o m)

inserts : {k l : ℕ} (o : ℕ) → Mergey k l → Mergey k (o + l)
inserts zero    m = m
inserts (suc o) m = insert (inserts o m)

weakFin : Weakening Fin
weakFin finish     k       = k
weakFin (copy m)   zero    = zero
weakFin (copy m)   (suc k) = suc (weakFin m k)
weakFin (insert m) k       = suc (weakFin m k)

data Env (T : ℕ → Set) : (k l : ℕ) → Set where
  []  : {l : ℕ} → Env T 0 l
  v∷_ : {k l : ℕ} → Env T k l → Env T (suc k) (suc l)
  _∷_ : {k l : ℕ} (t : T l) (ρ : Env T k l) → Env T (suc k) l

Substituting : (E T : ℕ → Set) → Set
Substituting E T = {k l : ℕ} (ρ : Env E k l) → T k → T l

record Freshey (T : ℕ → Set) : Set where
  field
    fresh : {k : ℕ} → T (suc k)
    weak  : Weakening T

substFin : {k l : ℕ} {T : ℕ → Set} (F : Freshey T) (ρ : Env T k l) → Fin k → T l
substFin F (v∷ ρ)  zero    = Freshey.fresh F
substFin F (t ∷ ρ) zero    = t
substFin F (v∷ ρ)  (suc v) = Freshey.weak F (insert finish) $ substFin F ρ v
substFin F (t ∷ ρ) (suc v) = substFin F ρ v

withFreshVars : {T : ℕ → Set} → Extending (Env T)
withFreshVars zero    ρ = ρ
withFreshVars (suc o) ρ = v∷ withFreshVars o ρ
