{-# OPTIONS --safe --without-K #-}
module Context.Base (Ty : Set) where

open import Data.Empty   using ( ; ⊥-elim)
open import Data.Product using (Σ ; _×_ ; _,_ ;  ; ∃₂ ; proj₂)
open import Data.Unit    using ( ; tt)

open import Relation.Binary.Definitions using (Reflexive ; Transitive)

private
  variable
    a b c d : Ty

infixl 6 _# _`,_
infix  5 _⊆_
infixl 5 _,,_

-----------
-- Contexts
-----------

data Ctx : Set where
  []   : Ctx
  _`,_ : (Γ : Ctx)  (a : Ty)  Ctx
  _#   : (Γ : Ctx)  Ctx            -- a lock 🔒

[#] : Ctx
[#] = [] #

[_] : Ty  Ctx
[_] a = [] `, a

variable
  Γ Γ' Γ'' ΓL ΓL' ΓL'' ΓLL ΓLR ΓR ΓR' ΓR'' ΓRL ΓRR : Ctx
  Δ Δ' Δ'' ΔL ΔL' ΔL'' ΔLL ΔLR ΔR ΔR' ΔR'' ΔRL ΔRR : Ctx
  Θ Θ' Θ'' ΘL ΘL' ΘL'' ΘLL ΘLR ΘR ΘR' ΘR'' ΘRL ΘRR : Ctx
  Ξ Ξ' Ξ'' ΞL ΞL' ΞL'' ΞLL ΞLR ΞR ΞR' ΞR'' ΞRL ΞRR : Ctx

-- append contexts (++)
_,,_ : Ctx  Ctx  Ctx
Γ ,, []       = Γ
Γ ,, (Δ `, x) = (Γ ,, Δ) `, x
Γ ,, (Δ #)    = (Γ ,, Δ) #

-- contexts free of locks
#-free : Ctx  Set
#-free []        = 
#-free (Γ `, _a) = #-free Γ
#-free ( #)    = 

-- context to left of the last lock
←# : Ctx  Ctx
←# []        = []
←# (Γ `, _a) = ←# Γ
←# (Γ #)     = Γ

-- context to the right of the last lock
#→ : Ctx  Ctx
#→ []       = []
#→ (Γ `, a) = #→ Γ `, a
#→ ( #)   = []

-------------
-- Weakenings
-------------

-- weakening relation
data _⊆_  : Ctx  Ctx  Set where
  base   : []  []
  drop   : (w : Γ  Δ)  Γ  Δ `, a
  keep   : (w : Γ  Δ)  Γ `, a  Δ `, a
  keep#  : (w : Γ  Δ)  Γ #  Δ #

{-
  Notes on _⊆_:

  In addition to the regular definition of weakening (`base`, `drop` and `keep`),
  we also allow weakening in the presence of locks:

  - `keep#` allows weakening under locks

  Disallowing weakening with locks in general ensures that values
  that depend on "local" assumptions cannot be boxed by simply
  weakening with locks.

-}

pattern drop[_] a w = drop {a = a} w
pattern keep[_] a w = keep {a = a} w

variable
  w w' w'' : Γ  Γ'

-- weakening is reflexive
idWk[_] : (Γ : Ctx)  Γ  Γ
idWk[_] []        = base
idWk[_] (Γ `, _a) = keep  idWk[ Γ ]
idWk[_] (Γ #)     = keep# idWk[ Γ ]

idWk = λ {Γ}  idWk[ Γ ]

-- weakening is transitive (or can be composed)
_∙_ : Θ  Δ  Δ  Γ  Θ  Γ
w        base     = w
w        drop  w' = drop  (w  w')
drop  w  keep  w' = drop  (w  w')
keep  w  keep  w' = keep  (w  w')
keep# w  keep# w' = keep# (w  w')

-- weakening that "generates a fresh variable"
fresh : Γ  Γ `, a
fresh = drop idWk

fresh[_] = λ {Γ} a  fresh {Γ} {a}

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

data Var : Ctx  Ty  Set where
  zero : Var (Γ `, a) a
  succ : (v : Var Γ a)  Var (Γ `, b) a

pattern v0 = zero
pattern v1 = succ v0
pattern v2 = succ v1

wkVar : Γ  Γ'  Var Γ a  Var Γ' a
wkVar (drop e) v        = succ (wkVar e v)
wkVar (keep e) zero     = zero
wkVar (keep e) (succ v) = succ (wkVar e v)

-- OBS: in general, Γ ⊈ Δ ,, Γ
leftWkVar : (v : Var Γ a)  Var (Δ ,, Γ) a
leftWkVar zero     = zero
leftWkVar (succ v) = succ (leftWkVar v)

--------------------
-- Context extension
--------------------

-- The three-place relation Ext θ relates contexts Γ, ΓL, and ΓR
-- exactly when Γ = ΓL ,, ΓR (cf. lemmas extIs,, and ,,IsExt
-- below). In other words, Ext θ is the graph of context concatenation
-- _,,_. The relation Ext θ Γ ΓL ΓR may be read as "Γ is ΓL extended
-- to the right with ΓR".
--
-- The flag θ specifies whether the context ΓR we are extending with
-- may contain locks (if set to tt) or not (if set to ff).
--
-- Ext is used below to define lock-free and arbitrary context
-- extensions LFExt and CExt, respectively, in a uniform way. The
-- relations LFExt and CExt in turn are used to define the modal
-- accessibility premises of the unbox term formers for λ_IK (see data
-- Tm in IK.Term.Base) and λ_IS4 (see data Tm in IS4.Term.Base),
-- respectively, in a uniform way.

data Flag : Set where
  tt ff : Flag

variable
  θ θ' : Flag

-- with locks?
WL : Flag  Set
WL tt = 
WL ff = 

data Ext (θ : Flag) : Ctx  Ctx  Ctx  Set where
  nil  : Ext θ Γ Γ []
  ext  : (e : Ext θ Γ ΓL ΓR)  Ext θ (Γ `, a) ΓL (ΓR `, a)
  ext# : WL θ  (e : Ext θ Γ ΓL ΓR)  Ext θ (Γ #) ΓL (ΓR #)

pattern nil[_] Γ   = nil  {Γ = Γ}
pattern ext[_] a e = ext  {a = a} e
pattern ext#-    e = ext# tt      e

-- Lock-free context extension (w/o locks, Ext flag set to ff)
--
-- The modal accessibility relation _◁_ for λ_IK defined in Figure 4
-- in the paper can equivalently be defined by Δ ◁ Γ = ∃ ΔR. LFExt Γ
-- (Δ #) ΔR.
--
-- Lock-free context extensions are also used to represent sequences
-- w : Γ ⊆ Γ `, a₁ `, … `, aₙ of drops in the "shift-unbox" conversion
-- rule unbox t (w · e) ≈ unbox (wkTm w t) e (cf. discussion below
-- Theorem 7 in the paper).
LFExt : Ctx  Ctx  Ctx  Set
LFExt = Ext ff

_◁IK_ = λ Δ Γ  Σ Ctx λ ΔR  LFExt Γ (Δ #) ΔR

-- Arbitrary context extension (possibly w/ locks, Ext flag set to tt)
--
-- The modal accessibility relation _◁_ for λ_IS4 defined in Figure 10
-- in the paper can equivalently be defined by Δ ◁ Γ = ∃ ΔR. CExt Γ Δ
-- ΔR.
CExt : Ctx  Ctx  Ctx  Set
CExt = Ext tt

_◁IS4_ = λ Δ Γ  Σ Ctx λ ΔR  CExt Γ Δ ΔR

pattern nil◁    = _ , nil
pattern ext◁  e = _ , ext     e
pattern ext#◁ e = _ , ext# tt e

-- extension that "generates a new context frame"
pattern new◁IK  = _ , nil
pattern new◁IS4 = _ , ext# tt nil

variable
  e e' e'' : Ext θ Γ ΓL ΓR

-- embed lock-free extensions into ones that extend with locks
upLFExt : LFExt Γ ΓL ΓR  Ext θ Γ ΓL ΓR
upLFExt nil     = nil
upLFExt (ext e) = ext (upLFExt e)

-- left identity of extension
extLId : CExt Γ [] Γ
extLId {Γ = []}       = nil
extLId {Γ =  `, _a} = ext     extLId
extLId {Γ =  #}     = ext# tt extLId

-- right identity of extension
extRId : Ext θ Γ Γ []
extRId = nil

-- extension that "generates a fresh variable"
freshExt : Ext θ (Γ `, a) Γ ([] `, a)
freshExt = ext nil

freshExt[_] = λ {θ} {Γ} a  freshExt {θ} {Γ} {a}

-- lock-free extensions yield a "right" weakening (i.e., adding variables on the right)
LFExtToWk : LFExt Γ ΓL ΓR  ΓL  Γ
LFExtToWk nil     = idWk
LFExtToWk (ext e) = drop (LFExtToWk e)

-- extension is assocative
extRAssoc : Ext θ ΓL ΓLL ΓLR  Ext θ Γ ΓL ΓR  Ext θ Γ ΓLL (ΓLR ,, ΓR)
extRAssoc el nil         = el
extRAssoc el (ext    er) = ext    (extRAssoc el er)
extRAssoc el (ext# x er) = ext# x (extRAssoc el er)

_∙Ext_ = extRAssoc

-------------------------------------
-- Operations on lock-free extensions
-------------------------------------

-- weaken the extension of a context
wkLFExt : (e : LFExt Γ (ΓL #) ΓR)  (w : Γ  Γ')  LFExt Γ' ((←# Γ') #) (#→ Γ')
wkLFExt e       (drop  w) = ext (wkLFExt e w)
wkLFExt nil     (keep# w) = nil
wkLFExt (ext e) (keep  w) = ext (wkLFExt e w)

-- left weaken the (lock-free) extension of a context
leftWkLFExt : (e : LFExt Γ ΓL ΓR)  LFExt (Δ ,, Γ) (Δ ,, ΓL) ΓR
leftWkLFExt nil     = nil
leftWkLFExt (ext e) = ext (leftWkLFExt e)

-- slice a weakening to the left of a lock
sliceLeft : (e : LFExt Γ (ΓL #) ΓR)  (w : Γ  Γ')  ΓL  ←# Γ'
sliceLeft e       (drop  w) = sliceLeft e w
sliceLeft (ext e) (keep  w) = sliceLeft e w
sliceLeft nil     (keep# w) = w

-- slice a weakening to the right of a lock
sliceRight : (e : LFExt Γ (ΓL #) ΓR)  (w : Γ  Γ')  ←# Γ' #  Γ'
sliceRight e w = LFExtToWk (wkLFExt e w)

-----------------------------------
-- Operations on general extensions
-----------------------------------

◁IS4-refl : Reflexive _◁IS4_
◁IS4-refl = nil◁

◁IS4-trans : Transitive _◁IS4_
◁IS4-trans (_ , Γ◁Δ) (_ , Δ◁Ε) = _ , extRAssoc Γ◁Δ Δ◁Ε

private
  -- we don't use factor1 anymore
  factor1 : Γ ◁IS4 Δ  Γ'  Γ   λ Δ'  Δ'  Δ × Γ' ◁IS4 Δ'
  factor1 nil◁        Γ'⊆Γ
    = _ , Γ'⊆Γ , nil◁
  factor1 (ext◁  Γ◁Δ) Γ'⊆Γ with factor1 (_ , Γ◁Δ) Γ'⊆Γ
  ... | Δ' , Δ'⊆Δ , Γ'◁Δ'
    = Δ' , drop Δ'⊆Δ , Γ'◁Δ'
  factor1 (ext#◁ Γ◁Δ) Γ'⊆Γ with factor1 (_ , Γ◁Δ) Γ'⊆Γ
  ... | Δ' , Δ'⊆Δ , Γ'◁Δ'
    = Δ' # , keep# Δ'⊆Δ , ◁IS4-trans Γ'◁Δ' (ext#◁ extRId)

  -- not used directly, but serves as a specification of
  -- what is expected from factorExt and factorWk
  factor2 : Γ ◁IS4 Δ  Δ  Δ'   λ Γ'  Γ  Γ' × Γ' ◁IS4 Δ'
  factor2 nil◁        Δ⊆Δ'
    = _ , Δ⊆Δ' , nil◁
  factor2 (ext◁  Γ◁Δ) Δ⊆Δ'
    = factor2 (_ , Γ◁Δ) (fresh  Δ⊆Δ')
  factor2 (ext#◁ Γ◁Δ) Δ⊆Δ' with factor2 (_ , Γ◁Δ) (sliceLeft extRId Δ⊆Δ')
  ... | Γ' , Γ⊆Γ' , Γ'◁Δ'
    = Γ' , Γ⊆Γ' , ◁IS4-trans Γ'◁Δ' (◁IS4-trans (ext#◁ extRId) (_ , upLFExt (wkLFExt extRId Δ⊆Δ')))

-- "Left" context of factoring (see type of factorWk and factorExt)
-- lCtx e w == proj₁ (factor2 (_ , e) w)
lCtx : Ext θ Γ ΓL ΓR  Γ  Γ'  Ctx
lCtx {Γ = Γ}      {Γ' = Γ'}       nil        w
  = Γ'
lCtx {Γ = Γ `, a} {Γ' = Γ' `, b}  (ext e)    (drop w)
  = lCtx (ext e) w
lCtx {Γ = Γ `, a} {Γ' = Γ' `, .a} (ext e)    (keep w)
  = lCtx e w
lCtx {Γ = Γ #} {Γ' = Γ' `, a}     (ext# f e) (drop w)
  = lCtx  (ext# f e) w
lCtx {Γ = Γ #} {Γ' = Γ' #}        (ext# f e) (keep# w)
  = lCtx e w

-- factorWk e w == proj₁ (proj₂ (factor2 (_ , e) w))
factorWk : (e : Ext θ Γ ΓL ΓR)  (w : Γ  Γ')  ΓL  lCtx e w
factorWk nil        w         = w
factorWk (ext e)    (drop w)  = factorWk (ext e) w
factorWk (ext e)    (keep w)  = factorWk e w
factorWk (ext# f e) (drop w)  = factorWk (ext# f e) w
factorWk (ext# f e) (keep# w) = factorWk e w

-- "Right" context of factoring (see type of factorExt)
-- rCtx e w == proj₁ (proj₂ (proj₂ (factor2 (_ , e) w)))
rCtx : Ext θ Γ ΓL ΓR  Γ  Γ'  Ctx
rCtx  {Γ = Γ}     {Γ' = Γ'}       nil        w
  = []
rCtx {Γ = Γ `, a} {Γ' = Γ' `, b}  (ext e)    (drop w)
  = rCtx (ext e) w `, b
rCtx {Γ = Γ `, a} {Γ' = Γ' `, .a} (ext e)    (keep w)
  = rCtx e w `, a
rCtx {Γ = Γ #}    {Γ' = Γ' `, a}  (ext# f e) (drop {a = a} w)
  = rCtx (ext# f e) w `, a
rCtx {Γ = Γ #}    {Γ' = Γ' #}     (ext# f e) (keep# w)
  = (rCtx e w) #

-- factorExt e w == proj₂ (proj₂ (proj₂ (factor2 (_ , e) w)))
factorExt : (e : Ext θ Γ ΓL ΓR)  (w : Γ  Γ')  Ext θ Γ' (lCtx e w) (rCtx e w)
factorExt nil        w         = nil
factorExt (ext    e) (drop w)  = ext    (factorExt (ext    e) w)
factorExt (ext    e) (keep w)  = ext    (factorExt e          w)
factorExt (ext# f e) (drop w)  = ext    (factorExt (ext# f e) w)
factorExt (ext# f e) (keep# w) = ext# f (factorExt e          w)

-------------------------------------------------------------------------------------
-- Substitutions (parameterized by terms `Tm` and modal accessibility relation `Acc`)
-------------------------------------------------------------------------------------

module Substitution
  (Tm          : (Γ : Ctx)  (a : Ty)  Set)
  (var         : {Γ : Ctx}  {a : Ty}  (v : Var Γ a)  Tm Γ a)
  (wkTm        : {Γ' Γ : Ctx}  {a : Ty}  (w : Γ  Γ')  (t : Tm Γ a)  Tm Γ' a)
  (Acc         : (Δ Γ ΓR : Ctx)  Set)
  {newR        : (Γ : Ctx)  Ctx}
  (new         :  {Γ : Ctx}  Acc (Γ #) Γ (newR Γ))
  (lCtx        : {Δ Γ ΓR Δ' : Ctx}  (e : Acc Δ Γ ΓR)  (w : Δ  Δ')  Ctx)
  (factorWk    :  {Δ Γ ΓR Δ' : Ctx} (e : Acc Δ Γ ΓR) (w : Δ  Δ')  Γ  lCtx e w)
  (rCtx        : {Δ Γ ΓR Δ' : Ctx}  (e : Acc Δ Γ ΓR)  (w : Δ  Δ')  Ctx)
  (factorExt   :  {Δ Γ ΓR Δ' : Ctx} (e : Acc Δ Γ ΓR) (w : Δ  Δ')  Acc Δ' (lCtx e w) (rCtx e w))
  where

  data Sub : Ctx  Ctx  Set where
    []   : Sub Δ []
    _`,_ : (σ : Sub Δ  Γ)  (t : Tm Δ a)       Sub Δ (Γ `, a)
    lock : (σ : Sub ΔL Γ)  (e : Acc Δ ΔL ΔR)  Sub Δ (Γ #)

  Sub- : Ctx  Ctx  Set
  Sub- Δ Γ = Sub Γ Δ

  variable
    s s' s'' : Sub Δ Γ
    σ σ' σ'' : Sub Δ Γ
    τ τ' τ'' : Sub Δ Γ

  -- composition operation for weakening after substitution
  trimSub : Δ  Γ  Sub Γ' Γ  Sub Γ' Δ
  trimSub base      []         = []
  trimSub (drop w)  (s `, x)   = trimSub w s
  trimSub (keep w)  (s `, x)   = (trimSub w s) `, x
  trimSub (keep# w) (lock s x) = lock (trimSub w s) x

  -- apply substitution to a variable
  substVar : Sub Γ Δ  Var Δ a  Tm Γ a
  substVar (s `, t)  zero     = t
  substVar (s `, _t) (succ v) = substVar s v

  -- weaken a substitution
  wkSub : Γ  Γ'  Sub Γ Δ  Sub Γ' Δ
  wkSub w []         = []
  wkSub w (s `, t)   = wkSub w s `, wkTm w t
  wkSub w (lock s e) = lock (wkSub (factorWk e w) s) (factorExt e w)

  -- NOTE: composition requires parallel substitution for terms

  -- "drop" the last variable in the context
  dropₛ : Sub Γ Δ  Sub (Γ `, a) Δ
  dropₛ s = wkSub fresh s

  -- "keep" the last variable in the context
  keepₛ : Sub Γ Δ  Sub (Γ `, a) (Δ `, a)
  keepₛ s = dropₛ s `, var zero

  -- "keep" the lock in the context
  keep#ₛ : Sub Γ Δ  Sub (Γ #) (Δ #)
  keep#ₛ s = lock s new

  -- embed a weakening to substitution
  embWk : Δ  Γ  Sub Γ Δ
  embWk base      = []
  embWk (drop  w) = dropₛ  (embWk w)
  embWk (keep  w) = keepₛ  (embWk w)
  embWk (keep# w) = keep#ₛ (embWk w)

  -- identity substitution
  idₛ : Sub Γ Γ
  idₛ = embWk idWk

  idₛ[_] = λ Γ  idₛ {Γ}

  ExtToSub : Acc Γ ΓL ΓR  Sub Γ (ΓL #)
  ExtToSub e = lock idₛ e

  module Composition
    (substTm     : {Δ Γ : Ctx}  {a : Ty}  (σ : Sub Δ Γ)  (t : Tm Γ a)  Tm Δ a)
    (lCtxₛ       : {Δ Γ ΓR Θ : Ctx}  (e : Acc Δ Γ ΓR)  (σ : Sub Θ Δ)  Ctx)
    (factorSubₛ  :  {Δ Γ ΓR Θ : Ctx} (e : Acc Δ Γ ΓR) (σ : Sub Θ Δ)  Sub (lCtxₛ e σ) Γ)
    (rCtxₛ       : {Δ Γ ΓR Θ : Ctx}  (e : Acc Δ Γ ΓR)  (σ : Sub Θ Δ)  Ctx)
    (factorExtₛ  :  {Δ Γ ΓR Θ : Ctx} (e : Acc Δ Γ ΓR) (σ : Sub Θ Δ)  Acc Θ (lCtxₛ e σ) (rCtxₛ e σ))
    where

    infixr 20 _∙ₛ_

    -- substitution composition
    _∙ₛ_ : Sub Δ Γ  Sub Δ' Δ  Sub Δ' Γ
    []        ∙ₛ s = []
    (s' `, t) ∙ₛ s = s' ∙ₛ s `, substTm s t
    lock s' e ∙ₛ s = lock (s' ∙ₛ factorSubₛ e s) (factorExtₛ e s)

Generated from commit 2fd14c996b195ef101dff8919e837907ca0a08aa.