module DSterm where

open import Data.Empty
open import Data.Nat

-- type
data typ : Set where
  Nat          : typ
  _⇒_cps[_,_] : typ  typ  typ  typ  typ

data conttyp : Set where
  _▷_ : typ  typ  conttyp

infix 15 _▷_
infix 17 _⇒_cps[_,_]

-- source term
mutual
  data value[_]_ (var : typ  Set) : typ  Set where
    -- x
    Var   : {τ₁ : typ}  var τ₁  value[ var ] τ₁
    -- n
    Num   :   value[ var ] Nat
    -- λx.M
    Fun   : {τ₁ τ₂ τ₃ τ₄ : typ} 
            (var τ₂  term[ var , τ₁  τ₃ ] τ₄) 
            value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ])
    -- S
    Shift : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
            value[ var ] (((τ₁  τ₂ cps[ τ₃ , τ₃ ])  τ₄ cps[ τ₄ , τ₅ ])
                           τ₁ cps[ τ₂ , τ₅ ])

  data term[_,_]_ (var : typ  Set) : conttyp  typ  Set where
    Val    : {τ₁ τ₂ : typ} 
             value[ var ] τ₁ 
             term[ var , τ₁  τ₂ ] τ₂
    NonVal : {τ : typ} {Δ : conttyp} 
             nonvalue[ var , Δ ] τ 
             term[ var , Δ ] τ

  data nonvalue[_,_]_ (var : typ  Set) : conttyp  typ  Set where
    -- M N
    App   : {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ : typ} 
            term[ var , (τ₂  τ₁ cps[ τ₃ , τ₄ ])  τ₅ ] τ₆ 
            term[ var , τ₂  τ₄ ] τ₅ 
            nonvalue[ var , τ₁  τ₃ ] τ₆
    -- Sk.M
    Shift2 : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
            (var (τ₁  τ₂ cps[ τ₃ , τ₃ ])  term[ var , τ₄  τ₄ ] τ₅) 
            nonvalue[ var , τ₁  τ₂ ] τ₅
    -- <M>
    Reset : {τ₁ τ₂ τ₃ : typ} 
            term[ var , τ₁  τ₁ ] τ₂ 
            nonvalue[ var , τ₂  τ₃ ] τ₃
    -- let x = M in N
    Let   : {τ₁ τ₄ τ₅ : typ} {τ₂▷τ₃ : conttyp} 
            term[ var , τ₁  τ₄ ] τ₅                 -- M
            (var τ₁  term[ var , τ₂▷τ₃ ] τ₄)     -- λx. N
            nonvalue[ var , τ₂▷τ₃ ] τ₅
            -- τ₂▷τ₃ を τ₂ ▷ τ₃ にすると、のちに embedContT できなくなる

-- outside-in

-- inside-out
data pcontext[_,_,_]_ (var : typ  Set) : conttyp  typ  typ  Set where
  -- []
  Hole  : {τ₁ τ₂ : typ} 
          pcontext[ var , τ₁  τ₂ , τ₁ ] τ₂
  -- K[[]@M]
  App₁  : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} {Δ : conttyp} 
          pcontext[ var , Δ , τ₁ ] τ₃ 
          term[ var , τ₂  τ₄ ] τ₅ 
          pcontext[ var , Δ , τ₂  τ₁ cps[ τ₃ , τ₄ ] ] τ₅
  -- K[V@[]]
  App₂  : {τ₁ τ₂ τ₃ τ₄ : typ} {Δ : conttyp} 
          value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ]) 
          pcontext[ var , Δ , τ₁ ] τ₃ 
          pcontext[ var , Δ , τ₂ ] τ₄
  -- K[Let x = [] in M]
  Let   : {τ₁ τ₂ τ₃ τ₄ : typ} {Δ : conttyp} 
          pcontext[ var , Δ , τ₁ ] τ₃                 -- K
          (var τ₂  term[ var , τ₁  τ₃ ] τ₄)         -- λx. M
          pcontext[ var , Δ , τ₂ ] τ₄

plug : {var : typ  Set}  {τ₁ τ₂ τ₃ : typ} {τ₄▷τ₅ : conttyp} 
       pcontext[ var , τ₄▷τ₅ , τ₁ ] τ₂ 
       term[ var , τ₁  τ₂ ] τ₃ 
       term[ var , τ₄▷τ₅ ] τ₃
plug Hole e = e
plug (App₁ k e₂) e = plug k (NonVal (App e e₂))
plug (App₂ v₁ k) e = plug k (NonVal (App (Val v₁) e))
plug (Let k e₂) e = plug k (NonVal (Let e e₂))

-- examples
-- λx.x
val1 : {var : typ  Set}  {τ₁ τ₂ : typ} 
       value[ var ] (τ₁  τ₁ cps[ τ₂ , τ₂ ])
val1 = Fun  x  Val (Var x))

-- λx.S(λk.k x)
val2 : {var : typ  Set}  {τ₁ τ₂ : typ} 
       value[ var ] (τ₁  τ₁ cps[ τ₂ , τ₂ ])
val2 = Fun  x  NonVal (App (Val Shift)
         (Val (Fun  k  NonVal (App (Val (Var k)) (Val (Var x))))))))

val2' : {var : typ  Set}  {τ₁ τ₂ : typ} 
        value[ var ] (τ₁  τ₁ cps[ τ₂ , τ₂ ])
val2' = Fun  x  NonVal (Shift2  k 
          NonVal (App (Val (Var k)) (Val (Var x))))))

-- λx.S(λk.x)
val3 : {var : typ  Set}  {τ₁ τ₂ τ₃ τ : typ} 
       value[ var ] (τ₁  τ₂ cps[ τ₃ , τ₁ ])
val3 {τ = τ} = Fun  x  NonVal (App (Val (Shift {τ₃ = τ}))
                                        (Val (Fun  k  Val (Var x))))))

val3' : {var : typ  Set}  {τ₁ τ₂ τ₃ τ : typ} 
        value[ var ] (τ₁  τ₂ cps[ τ₃ , τ₁ ])
val3' {τ = τ} = Fun  x  NonVal (Shift2 {τ₃ = τ}  k  Val (Var x))))

-- λxyzw. (x y) (z w)
val4 : {var : typ  Set}  {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ τ₇ τ₈ τ₉ τ₁₀ τ₁₁ : typ} 
       value[ var ]
        ((τ₁  (τ₂  τ₃ cps[ τ₄ , τ₅ ]) cps[ τ₆ , τ₇ ]) 
         (τ₁  ((τ₈  τ₂ cps[ τ₅ , τ₆ ])  (τ₈  τ₃ cps[ τ₄ , τ₇ ])
                 cps[ τ₉ , τ₉ ]) cps[ τ₁₀ , τ₁₀ ])
         cps[ τ₁₁ , τ₁₁ ])
val4 = Fun  x  Val (Fun  y  Val (Fun  z  Val (Fun  w 
         NonVal (App (NonVal (App (Val (Var x)) (Val (Var y))))
                     (NonVal (App (Val (Var z)) (Val (Var w))))))))))))

-- λxyzw. let m = x y in let n = z w in m n
val4' : {var : typ  Set}  {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ τ₇ τ₈ τ₉ τ₁₀ τ₁₁ : typ} 
       value[ var ]
        ((τ₁  (τ₂  τ₃ cps[ τ₄ , τ₅ ]) cps[ τ₆ , τ₇ ]) 
         (τ₁  ((τ₈  τ₂ cps[ τ₅ , τ₆ ])  (τ₈  τ₃ cps[ τ₄ , τ₇ ])
                 cps[ τ₉ , τ₉ ]) cps[ τ₁₀ , τ₁₀ ])
         cps[ τ₁₁ , τ₁₁ ])
val4' = Fun  x  Val (Fun  y  Val (Fun  z  Val (Fun  w 
          NonVal (Let (NonVal (App (Val (Var x)) (Val (Var y))))  m 
            NonVal (Let (NonVal (App (Val (Var z)) (Val (Var w))))  n 
              NonVal (App (Val (Var m)) (Val (Var n))))))))))))))

-- λxyzw. let m = x y in let n = z w in m n
val4'' : {var : typ  Set}  {τ₁ τ₂ τ₃ τ₅ τ₆ τ₇ τ₈ τ₉ τ₁₀ τ₁₁ : typ} 
         -- τ₃ = τ₄
       value[ var ]
        ((τ₁  (τ₂  τ₃ cps[ τ₃ , τ₅ ]) cps[ τ₆ , τ₇ ]) 
         (τ₁  ((τ₈  τ₂ cps[ τ₅ , τ₆ ])  (τ₈  τ₃ cps[ τ₃ , τ₇ ])
                 cps[ τ₉ , τ₉ ]) cps[ τ₁₀ , τ₁₀ ])
         cps[ τ₁₁ , τ₁₁ ])
val4'' = Fun  x  Val (Fun  y  Val (Fun  z  Val (Fun  w 
               plug (Let Hole  m 
                      plug (Let Hole  n 
                             plug Hole
                               (NonVal (App (Val (Var m)) (Val (Var n))))))
                        (NonVal (App (Val (Var z)) (Val (Var w))))))
                 (NonVal (App (Val (Var x)) (Val (Var y)))))))))))

{- KNormal:
Fun (λ x → Ret KVar
  (Fun (λ y → Ret KVar
    (Fun (λ z → Ret KVar
      (Fun (λ w →
        App (Var x) (Var y)
            (KLet (λ m →
              App (Var z) (Var w)
                  (KLet (λ n → App (Var m) (Var n) KVar)))))))))))
-}

-- λx.λy.y ((λz.z) x)
val5 : {var : typ  Set}  {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
       value[ var ]
       (τ₁  ((τ₁  τ₂ cps[ τ₃ , τ₄ ])  τ₂ cps[ τ₃ , τ₄ ])
        cps[ τ₅ , τ₅ ])
val5 = Fun  x  Val (Fun  y 
         NonVal (App (Val (Var y))
                     (NonVal (App (Val (Fun  z  Val (Var z))))
                                  (Val (Var x))))))))

-- interpreter
〚_〛 : typ  Set
 Nat  = 
 τ₂  τ₁ cps[ τ₃ , τ₄ ]  =
    τ₂   ( τ₁    τ₃ )   τ₄ 

mutual
  gv : {τ : typ}  value[ 〚_〛 ] τ   τ 
  gv (Var x) = x
  gv (Num n) = n
  gv (Fun e) = λ x k  g (e x) k
  gv Shift = λ v k  v  x₂ k₂  k₂ (k x₂))  x  x)

  g : {τ₁ τ₂ τ₃ : typ} 
      term[ 〚_〛 , τ₁  τ₂ ] τ₃  ( τ₁    τ₂ )   τ₃ 
  g (Val v) k = k (gv v)
  g (NonVal e) k = gp e k

  gp : {τ₁ τ₂ τ₃ : typ} 
       nonvalue[ 〚_〛 , τ₁  τ₂ ] τ₃  ( τ₁    τ₂ )   τ₃ 
  gp (App e₁ e₂) k = g e₁  v₁  g e₂  v₂  v₁ v₂ k))
  gp (Shift2 e) k = g (e  x₂ k₂  k₂ (k x₂)))  x  x)
  gp (Reset e) k = k (g e  x  x))
  gp (Let e₁ e₂) k = g e₁  v₁  g (e₂ v₁) k)

-- M[x:=V]
-- substitution relation
mutual
  data SubstV {var : typ  Set} : {τ₁ τ₂ : typ} 
              (var τ₁  value[ var ] τ₂) 
              value[ var ] τ₁ 
              value[ var ] τ₂  Set where
    -- (λx.x)[v] → v
    sVar=  : {τ₁ : typ} {v : value[ var ] τ₁} 
             SubstV  x  Var x) v v
    -- (λ_.x)[v] → x
    sVar≠  : {τ₁ τ₂ : typ} {v : value[ var ] τ₂} {x : var τ₁} 
             SubstV  _  Var x) v (Var x)
    -- (λ_.n)[v] → n
    sNum   : {τ₁ : typ} {v : value[ var ] τ₁} {n : } 
             SubstV  _  Num n) v (Num n)
    -- (λy.λx.ey)[v] → λx.e′
    sFun   : {τ τ₁ τ₂ τ₃ τ₄ : typ} 
             {e₁ : var τ₁  var τ  term[ var , τ₂  τ₃ ] τ₄} 
             {v : value[ var ] τ₁} 
             {e₁′ : var τ  term[ var , τ₂  τ₃ ] τ₄} 
             ((x : var τ)  Subst  y  (e₁ y) x) v (e₁′ x)) 
             SubstV  y  Fun (e₁ y)) v (Fun e₁′)
    -- (λ_.S)[v] → S
    sShift : {τ τ₁ τ₂ τ₃ τ₄ τ₅ : typ} {v : value[ var ] τ} 
             SubstV  _  Shift {τ₁ = τ₁} {τ₂} {τ₃} {τ₄} {τ₅}) v Shift

  data Subst {var : typ  Set} : {τ₁ τ₂ : typ} {Δ : conttyp} 
             (var τ₁  term[ var , Δ ] τ₂) 
             value[ var ] τ₁ 
             term[ var , Δ ] τ₂  Set where
    sVal   : {τ τ₁ τ₂ : typ} 
             {v₁ : var τ  value[ var ] τ₁} 
             {v : value[ var ] τ} 
             {v₁′ : value[ var ] τ₁} 
             SubstV v₁ v v₁′ 
             Subst {τ₂ = τ₂}  y  Val (v₁ y)) v (Val v₁′)
    sNonVal : {τ τ₄ : typ} {τ₁▷τ₃ : conttyp} 
             {e : var τ  nonvalue[ var , τ₁▷τ₃ ] τ₄} 
             {v : value[ var ] τ} 
             {e′ : nonvalue[ var , τ₁▷τ₃ ] τ₄} 
             SubstNV e v e′ 
             Subst  y  NonVal (e y)) v (NonVal e′)

  data SubstNV {var : typ  Set} : {τ₁ τ₄ : typ} {τ₂▷τ₃ : conttyp} 
             (var τ₁  nonvalue[ var , τ₂▷τ₃ ] τ₄) 
             value[ var ] τ₁ 
             nonvalue[ var , τ₂▷τ₃ ] τ₄  Set where
    sApp   : {τ τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ : typ} 
             {e₁ : var τ  term[ var , (τ₂  τ₁ cps[ τ₃ , τ₄ ])  τ₅ ] τ₆}
             {e₂ : var τ  term[ var , τ₂  τ₄ ] τ₅}
             {v : value[ var ] τ}
             {e₁′ : term[ var , (τ₂  τ₁ cps[ τ₃ , τ₄ ])  τ₅ ] τ₆}
             {e₂′ : term[ var , τ₂  τ₄ ] τ₅} 
             Subst e₁ v e₁′  Subst e₂ v e₂′ 
             SubstNV  y  App (e₁ y) (e₂ y)) v (App e₁′ e₂′)
    sShift2 : {τ τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
             {e : var τ₁ 
                  var (τ  τ₂ cps[ τ₃ , τ₃ ])  term[ var , τ₄  τ₄ ] τ₅} 
             {v : value[ var ] τ₁} 
             {e′ : var (τ  τ₂ cps[ τ₃ , τ₃ ]) 
                   term[ var , τ₄  τ₄ ] τ₅} 
             ((x : var (τ  τ₂ cps[ τ₃ , τ₃ ])) 
              Subst  y  (e y) x) v (e′ x)) 
             SubstNV  y  Shift2 (e y)) v (Shift2 e′)
    sReset : {τ τ₁ τ₂ τ₄ : typ} 
             {e₁ : var τ  term[ var , τ₁  τ₁ ] τ₂} 
             {v : value[ var ] τ} 
             {e₁′ : term[ var , τ₁  τ₁ ] τ₂} 
             Subst e₁ v e₁′ 
             SubstNV {τ₄ = τ₄}  y  Reset (e₁ y))
                     v
                     (Reset e₁′)
    sLet   : {τ τ₁ β γ : typ} {τ₂▷α : conttyp} 
             {e₁ : var τ  term[ var , τ₁  β ] γ} 
             {e₂ : var τ  (var τ₁  term[ var , τ₂▷α ] β)} 
             {v : value[ var ] τ} 
             {e₁′ : term[ var , τ₁  β ] γ} 
             {e₂′ : var τ₁  term[ var , τ₂▷α ] β} 
             ((x : var τ₁)  Subst  y  (e₂ y) x) v (e₂′ x)) 
             Subst e₁ v e₁′ 
             SubstNV  y  Let (e₁ y) (e₂ y)) v (Let e₁′ e₂′)

data SubstC  {var : typ  Set} : {τ₁ τ₂ τ₃ : typ} {Δ : conttyp} 
             (var τ₁  pcontext[ var , Δ , τ₃ ] τ₂) 
             value[ var ] τ₁ 
             pcontext[ var , Δ , τ₃ ] τ₂  Set where

  sHole  :  {τ₁ τ₂ τ₃ : typ} 
            {v : value[ var ] τ₁} 
            SubstC {τ₂ = τ₂}{τ₃ = τ₃}  x  Hole) v Hole

  sApp₁  :  {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ τ₇ : typ} 
            {c₁ : var τ₁  pcontext[ var , τ₆  τ₇ , τ₁ ] τ₃} 
            {c₂ : pcontext[ var , τ₆  τ₇ , τ₁ ] τ₃} 
            {e₁ : var τ₁  term[ var , τ₂  τ₄ ] τ₅} 
            {e₂ : term[ var , τ₂  τ₄ ] τ₅} 
            {v : value[ var ] τ₁} 
            Subst e₁ v e₂ 
            SubstC c₁ v c₂ 
            SubstC  x  App₁ (c₁ x) (e₁ x)) v (App₁ c₂ e₂)

  sApp₂  :  {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ : typ} 
            {v₁ : var τ₁  value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ])} 
            {v₂ : value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ])} 
            {c₁ : var τ₁  pcontext[ var , τ₅  τ₆ , τ₁ ] τ₃} 
            {c₂ : pcontext[ var , τ₅  τ₆ , τ₁ ] τ₃} 
            {v : value[ var ] τ₁} 
            SubstV v₁ v v₂ 
            SubstC c₁ v c₂ 
            SubstC  x  App₂ (v₁ x) (c₁ x)) v (App₂ v₂ c₂)

  sLet   :  {τ τ₁ τ₂ τ₃ τ₄ : typ} {Δ : conttyp} 
            {c₁ : var τ  pcontext[ var , Δ , τ₁ ] τ₃} 
            {c₂ : pcontext[ var , Δ , τ₁ ] τ₃} 
            {e₁ : var τ  (var τ₂  (term[ var , τ₁  τ₃ ] τ₄))} 
            {e₂ : var τ₂  term[ var , τ₁  τ₃ ] τ₄} 
            {v : value[ var ] τ} 
            SubstC c₁ v c₂ 
            ((x : var τ₂)  Subst  y  e₁ y x) v (e₂ x)) 
            SubstC  x  Let (c₁ x)  y  e₁ x y)) v (Let c₂  y  e₂ y))

mutual
  SubstV≠ : {var : typ  Set} {τ₁ τ : typ} 
            (v₁ : value[ var ] τ₁) 
            {v : value[ var ] τ} 
            SubstV  y  v₁) v v₁
  SubstV≠ (Var x) = sVar≠
  SubstV≠ (Num n) = sNum
  SubstV≠ (Fun e) = sFun  x  Subst≠ (e x))
  SubstV≠ Shift = sShift

  Subst≠ : {var : typ  Set} {τ τ₄ : typ} {τ₁▷τ₃ : conttyp} 
           (e : term[ var , τ₁▷τ₃ ] τ₄) 
           {v : value[ var ] τ} 
           Subst  y  e) v e
  Subst≠ (Val v) = sVal (SubstV≠ v)
  Subst≠ (NonVal e) = sNonVal (SubstNV≠ e)

  SubstNV≠ : {var : typ  Set} {τ τ₄ : typ} {τ₁▷τ₃ : conttyp} 
             (e : nonvalue[ var , τ₁▷τ₃ ] τ₄) 
             {v : value[ var ] τ} 
             SubstNV  y  e) v e
  SubstNV≠ (App (Val v₁) (Val v₂)) =
    sApp (sVal (SubstV≠ v₁)) (sVal (SubstV≠ v₂))
  SubstNV≠ (App (Val v₁) (NonVal e₂)) =
    sApp (sVal (SubstV≠ v₁)) (sNonVal (SubstNV≠ e₂))
  SubstNV≠ (App (NonVal e₁) (Val v₂)) =
    sApp (sNonVal (SubstNV≠ e₁)) (sVal (SubstV≠ v₂))
  SubstNV≠ (App (NonVal e₁) (NonVal e₂)) =
    sApp (sNonVal (SubstNV≠ e₁)) (sNonVal (SubstNV≠ e₂))
  SubstNV≠ (Shift2 e) = sShift2  k  Subst≠ (e k))
  SubstNV≠ (Reset e) = sReset (Subst≠ e)
  SubstNV≠ (Let e₁ e₂) = sLet  x  Subst≠ (e₂ x)) (Subst≠ e₁)

-- reduction rules
data Reduce {var : typ  Set} : {β : typ} {τ▷α : conttyp} 
            term[ var , τ▷α ] β 
            term[ var , τ▷α ] β  Set where
  -- (λx.M)V -> M[x:=V]
  RBetaV : {τ τ₁ τ₂ τ₃ : typ} 
           (e₁ : var τ  term[ var , τ₁  τ₂ ] τ₃) 
           (v₂ : value[ var ] τ) 
           (e₁′ : term[ var , τ₁  τ₂ ] τ₃) 
           (sub : Subst e₁ v₂ e₁′) 
           Reduce (NonVal (App (Val (Fun e₁)) (Val v₂)))
                  e₁′
  -- λx.V@x -> V
  REtaV  : {τ₁ τ₂ τ₃ τ₄ β : typ} 
           (v : value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ])) 
           Reduce {β = β}
                  (Val (Fun  x  NonVal (App (Val v) (Val (Var x))))))
                  (Val v)
  -- let x = V in M -> M[x:=V]
  RBetaLet : {τ₁ τ₄ : typ} {τ₂▷τ₃ : conttyp} 
           (v₁ : value[ var ] τ₁) 
           (e₂ : var τ₁  term[ var , τ₂▷τ₃ ] τ₄) 
           (e₂′ : term[ var , τ₂▷τ₃ ] τ₄) 
           (sub : Subst e₂ v₁ e₂′) 
           Reduce (NonVal (Let (Val v₁) e₂))
                  e₂′
  -- let x = M in x -> M
  REtaLet : {τ₁ τ₂ τ₃ : typ} 
           (e₁ : term[ var , τ₁  τ₂ ] τ₃) 
           Reduce (NonVal (Let e₁  x  Val (Var x))))
                  e₁
  -- let y = (let x = L in M) in N -> let x = L in let y = M in N
  RAssoc : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} {τ₇▷τ₈ : conttyp} 
           (e₁ : term[ var , τ₁  τ₂ ] τ₃) 
           (e₂ : var τ₁  term[ var , τ₄  τ₅ ] τ₂) 
           (e₃ : var τ₄  term[ var , τ₇▷τ₈ ] τ₅) 
           Reduce (NonVal (Let (NonVal (Let e₁  x  e₂ x)))  y  e₃ y)))
                  (NonVal (Let e₁  x  NonVal (Let (e₂ x)  y  e₃ y)))))
  -- P@N -> let x = P in x@N
  RLet1  : {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ : typ} 
           (e₁ : nonvalue[ var , (τ₂  τ₁ cps[ τ₃ , τ₄ ])  τ₅ ] τ₆) 
           (e₂ : term[ var , τ₂  τ₄ ] τ₅) 
           Reduce (NonVal (App (NonVal e₁) e₂))
                  (NonVal (Let (NonVal e₁)  x 
                            NonVal (App (Val (Var x)) e₂))))
  -- V@Q -> let y = Q in V@y
  RLet2  : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
           {v₁ : value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ])} 
           (e₂ : nonvalue[ var , τ₂  τ₄ ] τ₅) 
           Reduce (NonVal (App (Val v₁) (NonVal e₂)))
                  (NonVal (Let (NonVal e₂)  y 
                            NonVal (App (Val v₁) (Val (Var y))))))
  -- <J[S@V]> -> <V@(λy.<J[y]>)>
  RShift : {τ₁ τ₂ τ₃ τ₄ τ₅ β : typ} 
           (v : value[ var ]
                ((τ₁  τ₂ cps[ τ₃ , τ₃ ])  τ₄ cps[ τ₄ , τ₅ ])
               ) 
           (j : pcontext[ var , τ₄  τ₄ , τ₁ ] τ₂) 
           Reduce {β = β}
                  (NonVal (Reset (plug j (NonVal (App (Val Shift) (Val v))))))
                  (NonVal (Reset (NonVal (App (Val v)
                    (Val (Fun  y 
                      NonVal (Reset (plug j (Val (Var y)))))))))))
  -- <J[Sk.M]> -> <(λk.M)@(λy.<J[y]>)>
  RShift2 : {τ₁ τ₂ τ₃ τ₄ τ₅ β : typ} 
           (e : var (τ₁  τ₂ cps[ τ₃ , τ₃ ])  term[ var , τ₄  τ₄ ] τ₅) 
           (j : pcontext[ var , τ₄  τ₄ , τ₁ ] τ₂) 
           Reduce {β = β}
                  (NonVal (Reset (plug j (NonVal (Shift2 e)))))
                  (NonVal (Reset (NonVal (App (Val (Fun e))
                    (Val (Fun  y 
                      NonVal (Reset (plug j (Val (Var y)))))))))))
  -- <V> -> V
  RReset : {τ₁ β : typ} 
           (v₁ : value[ var ] τ₁) 
           Reduce {β = β} (NonVal (Reset (Val v₁))) (Val v₁)

  -- congruence rules
  RFun   : {τ₁ τ₂ τ₃ τ₄ β : typ} 
           {e e′ : var τ₂  term[ var , τ₁  τ₃ ] τ₄} 
           ((x : var τ₂)  Reduce (e x) (e′ x)) 
           Reduce {β = β} (Val (Fun e)) (Val (Fun e′))
  RApp₁  : {τ₁ τ₂ τ₃ τ₄ τ₅ τ₆ : typ} 
           {e₁ e₁′ : term[ var , (τ₂  τ₁ cps[ τ₃ , τ₄ ])  τ₅ ] τ₆} 
           {e₂ : term[ var , τ₂  τ₄ ] τ₅} 
           Reduce e₁ e₁′ 
           Reduce (NonVal (App e₁ e₂)) (NonVal (App e₁′ e₂))
  RApp₂  : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
           {v₁ : value[ var ] (τ₂  τ₁ cps[ τ₃ , τ₄ ])} 
           {e₂ e₂′ : term[ var , τ₂  τ₄ ] τ₅} 
           Reduce e₂ e₂′ 
           Reduce (NonVal (App (Val v₁) e₂)) (NonVal (App (Val v₁) e₂′))
  RLet₁  : {τ₁ β γ : typ} {τ₂▷α : conttyp} 
           {e₁ e₁′ : term[ var , τ₁  β ] γ} 
           {e₂ : (var τ₁  term[ var , τ₂▷α ] β)} 
           Reduce e₁ e₁′ 
           Reduce (NonVal (Let e₁ e₂)) (NonVal (Let e₁′ e₂))
  RLet₂  : {τ₁ β γ : typ} {τ₂▷α : conttyp} 
           {e₁ : term[ var , τ₁  β ] γ} 
           {e₂ e₂′ : (var τ₁  term[ var , τ₂▷α ] β)} 
           ((x : var τ₁)  Reduce (e₂ x) (e₂′ x)) 
           Reduce (NonVal (Let e₁ e₂)) (NonVal (Let e₁ e₂′))
  RShift₁ : {τ₁ τ₂ τ₃ τ₄ τ₅ : typ} 
           {e e′ : var (τ₁  τ₂ cps[ τ₃ , τ₃ ]) 
                   term[ var , τ₄  τ₄ ] τ₅} 
           ((x : var (τ₁  τ₂ cps[ τ₃ , τ₃ ]))  Reduce (e x) (e′ x)) 
           Reduce (NonVal (Shift2 e))
                  (NonVal (Shift2 e′))
  RReset₁ : {τ₁ τ₂ β : typ} 
           {e e′ : term[ var , τ₁  τ₁ ] τ₂} 
           Reduce e e′ 
           Reduce {β = β}
                  (NonVal (Reset e))
                  (NonVal (Reset e′))
  -- closure rules
  RId    : {β : typ} {τ▷α : conttyp } 
           {e : term[ var , τ▷α ] β} 
           Reduce e e
  RTrans : {β : typ} {τ▷α : conttyp } 
           {e₁ e₂ e₃ : term[ var , τ▷α ] β} 
           Reduce e₁ e₂ 
           Reduce e₂ e₃ 
           Reduce e₁ e₃

-- equational reasoning
open import Relation.Binary.PropositionalEquality

module Reasoning where

  infix  3 _∎
  infixr 2 _⟶⟨_⟩_ _≡⟨_⟩_
  infix  1 begin_

  begin_ : {var : typ  Set} {τ₃ : typ} {τ₁▷τ₂ : conttyp} 
           {e₁ e₂ : term[ var , τ₁▷τ₂ ] τ₃} 
           Reduce e₁ e₂  Reduce e₁ e₂
  begin_ red = red

  _⟶⟨_⟩_ : {var : typ  Set} {τ₃ : typ} {τ₁▷τ₂ : conttyp} 
            (e₁ {e₂ e₃} : term[ var , τ₁▷τ₂ ] τ₃) 
            Reduce e₁ e₂  Reduce e₂ e₃  Reduce e₁ e₃
  _⟶⟨_⟩_ e₁ {e₂} {e₃} e₁-red-e₂ e₂-red-e₃ = RTrans e₁-red-e₂ e₂-red-e₃

  _≡⟨_⟩_ : {var : typ  Set} {τ₃ : typ} {τ₁▷τ₂ : conttyp} 
           (e₁ {e₂ e₃} : term[ var , τ₁▷τ₂ ] τ₃) 
           e₁  e₂  Reduce e₂ e₃ 
           Reduce e₁ e₃
  _≡⟨_⟩_ e₁ {e₂} {e₃} refl e₂-red-e₃ = e₂-red-e₃

  _∎ : {var : typ  Set} {τ₃ : typ} {τ₁▷τ₂ : conttyp} 
       (e : term[ var , τ₁▷τ₂ ] τ₃)  Reduce e e
  _∎ e = RId

-- lemma

-- v does not reduce to nonval e
reduceVal : {var : typ  Set} {τ₁ τ₂ : typ}
            {v : value[ var ] τ₁}
            {e : nonvalue[ var , τ₁  τ₂ ] τ₂} 
            Reduce (Val v) (NonVal e)  
reduceVal (RTrans {e₂ = Val v} red₁ red₂) = reduceVal red₂
reduceVal (RTrans {e₂ = NonVal e} red₁ red₂) = reduceVal red₁

-- e -> e' => K[e] -> K[e']
reducePlug : {var : typ  Set} {τ₁ τ₂ τ₃ : typ} {τ₄▷τ₅ : conttyp}
             (k : pcontext[ var , τ₄▷τ₅ , τ₁ ] τ₂) 
             {e e' : term[ var , τ₁  τ₂ ] τ₃} 
             Reduce e e' 
             Reduce (plug k e) (plug k e')
reducePlug Hole red = red
reducePlug (App₁ k e₂) red = reducePlug k (RApp₁ red)
reducePlug (App₂ v₁ k) red = reducePlug k (RApp₂ red)
reducePlug (Let k e₂) red = reducePlug k (RLet₁ red)

-- (K[e])[v] = K[v][e[v]]
substPlug : {var : typ  Set} {τ₃ τ₄ τ₅ τ₆ : typ} {Δ : conttyp}
            {k : var τ₄  pcontext[ var , Δ , τ₅ ] τ₃} 
            {k′ : pcontext[ var , Δ , τ₅ ] τ₃} 
            {v : value[ var ] τ₄} 
            {e : var τ₄  term[ var , τ₅  τ₃ ] τ₆} 
            {e′ : term[ var , τ₅  τ₃ ] τ₆} 
            SubstC k v k′ 
            Subst  x  e x) v e′ 
            Subst  x  plug (k x) (e x)) v (plug k′ e′)
substPlug sHole sub = sub
substPlug (sApp₁ sub₁ subC) sub₂ = substPlug subC (sNonVal (sApp sub₂ sub₁))
substPlug (sApp₂ subV subC) sub =
  substPlug  subC (sNonVal (sApp (sVal subV) sub))
substPlug (sLet subC sub₁) sub₂ =
  substPlug subC (sNonVal (sLet  x  sub₁ x) sub₂))