-- When scopes are represented by lists of kinds, a variable of
-- a given kind is a position in such a list. This is a strongly
-- typed version of de Bruijn indices hence the name we picked
-- for Var's constructor:
-- * z for zero
-- * s for successor

module var where

open import indexed
open import Data.Sum hiding (map)
open import Data.List.Base hiding ([_])
open import Data.List.All using (All ; _∷_)
open import Function
open import Agda.Builtin.Equality


_─Scoped : Set → Set₁
I ─Scoped = I → List I → Set

module _ {I : Set} where

 data Var : I ─Scoped where
   z : {i : I} →    [          (i ∷_) ⊢ Var i ]
   s : {i j : I} →  [ Var i ⟶  (j ∷_) ⊢ Var i ]

 infixl 3 _─_
 _─_ : {i : I} (Γ : List I) → Var i Γ → List I
 _ ∷ Γ ─ z   = Γ
 σ ∷ Γ ─ s v = σ ∷ (Γ ─ v)

 get : {B : I → Set} {i : I} → [ Var i ⟶ All B ⟶ κ (B i) ]
 get z     (b  ∷ _)  = b
 get (s v) (_  ∷ bs) = get v bs

_<$>_ : {I J : Set} (f : I → J) {i : I} → [ Var i ⟶ Var (f i) ∘ map f ]
f <$> z    = z
f <$> s v  = s (f <$> v)

record Injective {I J : Set} (f : I → J) : Set where
  constructor mkInjective
  field inj : ∀ {i₁ i₂} → f i₁ ≡ f i₂ → i₁ ≡ i₂
open Injective public

Injective-inj₁ : ∀ {A B : Set} → Injective ((A → A ⊎ B) ∋ inj₁)
inj Injective-inj₁ refl = refl

Injective-inj₂ : ∀ {A B : Set} → Injective ((B → A ⊎ B) ∋ inj₂)
inj Injective-inj₂ refl = refl

_<$>⁻¹_ : {I J : Set} {f : I → J} → Injective f →
          {i : I} → [ Var (f i) ∘ map f ⟶ Var i ]
_<$>⁻¹_ {I} {J} {f} F = go _ refl refl where

  go : {i : I} {j : J} (is : List I) {js : List J} →
       f i ≡ j → map f is ≡ js → Var j js → Var i is
  go []        eq ()   z
  go []        eq ()   (s v)
  go (i ∷ is)  eq refl z rewrite inj F eq = z
  go (i ∷ is)  eq refl (s v) = s (go is eq refl v)

injectˡ : {I : Set} {i : I} (ys : List I) → [ Var i ⟶ (_++ ys) ⊢ Var i ]
injectˡ k z      = z
injectˡ k (s v)  = s (injectˡ k v)

injectʳ : {I : Set} {i : I} (ys : List I) → [ Var i ⟶ (ys ++_) ⊢ Var i ]
injectʳ []        v = v
injectʳ (y ∷ ys)  v = s (injectʳ ys v)