------------------------------------------------------------------------
-- Contexts, variables, substitutions, etc.
------------------------------------------------------------------------

{-# OPTIONS --universe-polymorphism #-}

-- Based on Conor McBride's "Outrageous but Meaningful Coincidences:
-- Dependent type-safe syntax and evaluation".

-- The contexts and variables are parametrised by a universe.

open import Universe

module Data.Context {u e} (Uni : Universe u e) where

open Universe.Universe Uni

open import Data.Product as Prod
open import Data.Unit
open import Function
open import Level

------------------------------------------------------------------------
-- Contexts and "types"

mutual

  -- Contexts.

  infixl 5 _▻_

  data Ctxt : Set (u  e) where
    ε   : Ctxt
    _▻_ : (Γ : Ctxt) (σ : Type Γ)  Ctxt

  -- Semantic types: maps from environments to universe codes.

  Type : Ctxt  Set (u  e)
  Type Γ = Env Γ  U

  -- Interpretation of contexts: environments.

  Env : Ctxt  Set e
  Env ε       = Lift 
  Env (Γ  σ) = Σ (Env Γ) λ γ  El (σ γ)

-- Type signature for variables, terms, etc.

Term-like : ( : Level)  Set _
Term-like  = (Γ : Ctxt)  Type Γ  Set 

-- Semantic values: maps from environments to universe values.

Value : Term-like _
Value Γ σ = (γ : Env Γ)  El (σ γ)

------------------------------------------------------------------------
-- "Substitutions"

-- Semantic substitutions or context morphisms: maps from environments
-- to environments.

infixr 4 _⇨_

_⇨_ : Ctxt  Ctxt  Set _
Γ  Δ = Env Δ  Env Γ

-- Maps between types.

infixr 4 _⇨₁_

_⇨₁_ :  {Γ}  Type Γ  Type Γ  Set _
σ ⇨₁ τ =  {γ}  El (τ γ)  El (σ γ)

-- Application of substitutions to types.
--
-- Note that this operation is composition of functions. I have chosen
-- not to give a separate name to the identity substitution, which is
-- simply the identity function, nor to reverse composition of
-- substitutions, which is composition of functions.

infixl 8 _/_

_/_ :  {Γ Δ}  Type Γ  Γ  Δ  Type Δ
σ / ρ = σ  ρ

-- Application of substitutions to values.

infixl 8 _/v_

_/v_ :  {Γ Δ σ}  Value Γ σ  (ρ : Γ  Δ)  Value Δ (σ / ρ)
v /v ρ = v  ρ

-- Weakening.

wk :  {Γ σ}  Γ  Γ  σ
wk = proj₁

-- Extends a substitution with another value.

infixl 5 _►_

_►_ :  {Γ Δ σ} (ρ : Γ  Δ)  Value Δ (σ / ρ)  Γ  σ  Δ
_►_ = <_,_>

-- A substitution which only replaces the first "variable".

sub :  {Γ σ}  Value Γ σ  Γ  σ  Γ
sub v = id  v

-- One can construct a substitution between two non-empty contexts by
-- supplying two functions, one which handles the last element and one
-- which handles the rest.

infixl 10 _↑_

_↑_ :  {Γ Δ σ τ} (ρ : Γ  Δ)  σ / ρ ⇨₁ τ  Γ  σ  Δ  τ
_↑_ = Prod.map

-- Lifting.

infix 10 _↑

_↑ :  {Γ Δ σ} (ρ : Γ  Δ)  Γ  σ  Δ  σ / ρ
ρ  = ρ  id

------------------------------------------------------------------------
-- Variables

-- Variables (de Bruijn indices).

infix 4 _∋_

data _∋_ : Term-like (u  e) where
  zero :  {Γ σ}                Γ  σ  σ / wk
  suc  :  {Γ σ τ} (x : Γ  σ)  Γ  τ  σ / wk

-- Interpretation of variables: a lookup function.

lookup :  {Γ σ}  Γ  σ  Value Γ σ
lookup zero    (γ , v) = v
lookup (suc x) (γ , v) = lookup x γ

-- Application of substitutions to variables.

infixl 8 _/∋_

_/∋_ :  {Γ Δ σ}  Γ  σ  (ρ : Γ  Δ)  Value Δ (σ / ρ)
x /∋ ρ = lookup x /v ρ

------------------------------------------------------------------------
-- Context extensions

mutual

  -- Context extensions.

  infixl 5 _▻_

  data Ctxt⁺ (Γ : Ctxt) : Set (u  e) where
    ε   : Ctxt⁺ Γ
    _▻_ : (Γ⁺ : Ctxt⁺ Γ) (σ : Type (Γ ++ Γ⁺))  Ctxt⁺ Γ

  -- Appends a context extension to a context.

  infixl 5 _++_

  _++_ : (Γ : Ctxt)  Ctxt⁺ Γ  Ctxt
  Γ ++ ε        = Γ
  Γ ++ (Γ⁺  σ) = (Γ ++ Γ⁺)  σ

mutual

  -- Application of substitutions to context extensions.

  infixl 8 _/⁺_

  _/⁺_ :  {Γ Δ}  Ctxt⁺ Γ  Γ  Δ  Ctxt⁺ Δ
  ε        /⁺ ρ = ε
  (Γ⁺  σ) /⁺ ρ = Γ⁺ /⁺ ρ  σ / ρ ↑⋆ Γ⁺

  -- N-ary lifting of substitutions.

  infixl 10 _↑⋆_

  _↑⋆_ :  {Γ Δ} (ρ : Γ  Δ)   Γ⁺  Γ ++ Γ⁺  Δ ++ Γ⁺ /⁺ ρ
  ρ ↑⋆ ε        = ρ
  ρ ↑⋆ (Γ⁺  σ) = (ρ ↑⋆ Γ⁺)