{-# OPTIONS --no-postfix-projections #-}

module Inception.Sub.ValueMachine (R : Set) where

open import Data.Product using (proj₁; proj₂; _,_; <_,_>; curry; _×_; Σ; ; Σ-syntax; ∃-syntax)
open import Function.Base using (const; _∘_; _$_)

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; cong₂; cong-app; dcong₂; sym; trans; subst; subst₂)
open Eq.≡-Reasoning

open import Inception.Sub.Syntax
open import Inception.Sub.CPS R

open import Data.Unit
open import Data.Nat
open import Data.List using (List; _∷_; []; _++_)

import Relation.Binary.HeterogeneousEquality as H

variable
  X X' Y Y' Z Z' T◾ T◾' : Ty
  Γ' Γ'' Δ' : Ctx
  n m n₁ n₂ n₃ n₄ m₁ m₂ m₃ m₄ : 

≤-trans : n₁  n₂  n₂  n₃  n₁  n₃
≤-trans {n₁ = zero} {n₂ = n₂} {n₃ = n₃} n₁≤n₂ n₂≤n₃ = z≤n
≤-trans {n₁ = suc n₁} {n₂ = suc n₂} {n₃ = suc n₃} (s≤s n₁≤n₂) (s≤s n₂≤n₃) = s≤s (≤-trans n₁≤n₂ n₂≤n₃)

≤-refl : n  n
≤-refl {n = zero} = z≤n
≤-refl {n = suc n} = s≤s ≤-refl

n≤sn : n  suc n
n≤sn {n = zero} = z≤n
n≤sn {n = suc n} = s≤s n≤sn

n≤sm : n  m  n  suc m
n≤sm {n = zero} {m = zero} n≤m = n≤sn
n≤sm {n = zero} {m = suc m} n≤m = z≤n
n≤sm {n = suc n} {m = suc m} (s≤s n≤m) = s≤s (≤-trans n≤sn (s≤s n≤m))

p≤p : suc n  suc m  n  m
p≤p (s≤s sn≤sm) = sn≤sm

p≤n : suc n  m  n  m
p≤n {m = suc m} (s≤s sn≤m) = n≤sm sn≤m

--pred' : suc n ≤ m → Σ[ p ∈ ℕ ] ( m ≡ suc p )
--pred' {n = n} {m = m} sn≤m = {!sn≤m!}

pred-eq : suc n  m  m  suc (pred m)
pred-eq {n = zero} {m = suc m} sn≤m = refl
pred-eq {n = suc n} {m = suc m} sn≤m = refl

n+z : (n : )  n + zero  n
n+z zero = refl
n+z (suc n) = cong suc (n+z n)

--{-# REWRITE n+z #-}

-----------------------------------------------------

+-assoc : {n₁ n₂ n₃ : }  n₁ + n₂ + n₃  n₁ + (n₂ + n₃)
+-assoc {zero} {n₂} {n₃} = refl
+-assoc {suc n₁} {n₂} {n₃} rewrite +-assoc {n₁} {n₂} {n₃} = refl

+-comm : n + m  m + n
+-comm {n = zero} {m = zero} = refl
+-comm {n = zero} {m = suc m} = cong suc (+-comm {n = zero} {m = m})
+-comm {n = suc n} {m = zero} = cong suc (+-comm {n = n} {m = zero})
+-comm {n = suc n} {m = suc m} rewrite +-comm {n = n} {m = suc m} | +-comm {n = m} {m = suc n} | +-comm {n = m} {m = n} = refl

*-comm : n * m  m * n
*-comm {n = zero} {m = zero} = refl
*-comm {n = zero} {m = suc m} = *-comm {n = zero} {m = m}
*-comm {n = suc n} {m = zero} = *-comm {n = n} {m = zero}
*-comm {n = suc n} {m = suc m}
  rewrite *-comm {n = n} {m = suc m} | *-comm {n = m} {m = suc n}
    | *-comm {n = n} {m = m}
    | sym (+-assoc {n₁ = m} {n₂ = n} {n₃ = m * n})
    | sym (+-assoc {n₁ = n} {n₂ = m} {n₃ = m * n})
    | +-comm {n = n} {m = m}
    = refl

-----------------------------------------------------

+-≤-cong : (n₁  n₃)  (n₂  n₄)  (n₁ + n₂  n₃ + n₄)
+-≤-cong z≤n z≤n = z≤n
+-≤-cong {n₃ = n₃} z≤n (s≤s {m = m} {n = n} n₂≤n₄) rewrite +-comm {n = n₃} {m = suc n} | +-comm {n = n} {m = n₃} = s≤s (+-≤-cong z≤n n₂≤n₄)
+-≤-cong (s≤s n₁≤n₃) n₂≤n₄ = s≤s (+-≤-cong n₁≤n₃ n₂≤n₄)

snm : suc (n + m)  n + (suc m)
snm {n = zero} {m = m} = refl
snm {n = suc n} {m = m} = cong suc snm

+-≤-cong-rev-left : (n + m₁  n + m₂)  (m₁  m₂)
+-≤-cong-rev-left {n = zero} m₁≤m₂ = m₁≤m₂
+-≤-cong-rev-left {n = suc n} {m₁ = m₁} {m₂ = m₂} m₁≤m₂ rewrite snm {n = n} {m = m₁} | snm {n = n} {m = m₂} = p≤p (+-≤-cong-rev-left m₁≤m₂)

*-≤-cong : (n₁  n₃)  (n₂  n₄)  (n₁ * n₂  n₃ * n₄)
*-≤-cong z≤n z≤n = z≤n
*-≤-cong z≤n (s≤s n₂≤n₄) = z≤n
*-≤-cong (s≤s {m = m} n₁≤n₃) z≤n rewrite *-comm {n = m} {m = zero} = z≤n
*-≤-cong (s≤s n₁≤n₃) (s≤s n₂≤n₄) = s≤s (+-≤-cong n₂≤n₄ (*-≤-cong n₁≤n₃ (s≤s n₂≤n₄)))

n≤n+m : n  n + m
n≤n+m {n = zero} {m = m} = z≤n
n≤n+m {n = suc n} {m = m} = s≤s n≤n+m

n≤m+n : n  m + n
n≤m+n {n = n} {m = m} rewrite +-comm {n = m} {m = n} = n≤n+m

n*sm≡n+n*m : (n : )  (m : )  n * suc m  n + n * m
n*sm≡n+n*m n m rewrite *-comm {n = n} {m = suc m} | *-comm {n = n} {m = m} = refl

n*sm≡n+m*n : (n : )  (m : )  n * suc m  n + m * n
n*sm≡n+m*n n m rewrite *-comm {n = n} {m = suc m} = refl

-----------------------------------------------------

module VMain {R₀ : Ty} (k₀ :  R₀   R) where

  infixl 27 _﹐_
  infixl 27 _﹐﹝_╎_﹞
  infix  26 ⭭_
  infix  26 ⇡_
  infixr 25 _⊲_∷_
  infix  20 ∘_
  infix  20 ∙_
  infixr 17 _→ᵛ⟨_⟩.
  infixr 15 _→ᵛ⟨_⟩_
  infix  15 _→ᵛ_
  infix  15 _→ᴸ_
  infixr 10 _⨾_

  data IsEmpty : Set where
      non-empty : IsEmpty
      empty : IsEmpty

  variable
      b : IsEmpty

  data V̲a̲l̲ : Ctx  Ty  Set where

      l̲a̲m̲ : (Γ  X) ⊢ᶜ Y  V̲a̲l̲ Γ (X `⇒ Y)

      pa̲i̲r̲ : V̲a̲l̲ Γ X  V̲a̲l̲ Γ Y  V̲a̲l̲ Γ (X  Y)

      u̲n̲i̲t̲ : V̲a̲l̲ Γ `Unit

      v̲a̲r̲  : (i : Γ  `V)  V̲a̲l̲ Γ `V

  toVal : V̲a̲l̲ Γ X  Γ ⊢ᵛ X
  toVal (l̲a̲m̲ W) = lam W
  toVal (pa̲i̲r̲ LHS RHS) = pair (toVal LHS) (toVal RHS)
  toVal (u̲n̲i̲t̲) = unit
  toVal (v̲a̲r̲ i) = var i

  wk-v̲a̲l̲ : Wk Γ Δ  V̲a̲l̲ Δ X  V̲a̲l̲ Γ X
  wk-v̲a̲l̲ π (l̲a̲m̲ W) = l̲a̲m̲ ((wk-comp (wk-cong π) W))
  wk-v̲a̲l̲ π (pa̲i̲r̲ LHS RHS) = pa̲i̲r̲ (wk-v̲a̲l̲ π LHS) (wk-v̲a̲l̲ π RHS)
  wk-v̲a̲l̲ π u̲n̲i̲t̲ = u̲n̲i̲t̲
  wk-v̲a̲l̲ π (v̲a̲r̲ i) = v̲a̲r̲ (wk-mem π i)

  wk-comm : {M : V̲a̲l̲ Γ X}  {π : Wk Δ Γ}  wk-val π (toVal M)  toVal (wk-v̲a̲l̲ π M)
  wk-comm {Γ = Γ} {Δ = Δ} {M = l̲a̲m̲ W} {π = π} = refl
  wk-comm {Γ = Γ} {Δ = Δ} {M = pa̲i̲r̲ LHS RHS} {π = π} = trans (cong  x  pair x _) wk-comm) ((cong  x  pair _ x) wk-comm))
  wk-comm {Γ = Γ} {Δ = Δ} {M = u̲n̲i̲t̲} {π = π} = refl
  wk-comm {Γ = Γ} {Δ = Δ} {M = v̲a̲r̲ i} {π = π} = refl

  data Env : (Γ : Ctx)  Set

  data CompStack : (Δ : Ctx)  (X : Ty)  Set

  topCsEnv : CompStack Δ X  Env Δ
  ⟦_⟧ᴱ : (E : Env Γ)   Γ ⟧ˣ
  ⟦_⟧ᶜˢ : (cs : CompStack Δ X)  K  X   K  R₀ 

  data CompStack  where

           :   CompStack ε R₀

      _⊲_⦂⦂_    : (Γ  Z) ⊢ᶜ X  (γ : Env Γ)  (tail : CompStack Δ X)  {π : Wk Γ Δ}  {wk≡ :  π ⟧ʷ  γ ⟧ᴱ   topCsEnv tail ⟧ᴱ}  CompStack Γ Z

  data C̲o̲m̲p : Ctx  Ty  Set
  data C̲o̲m̲p where

      r̲e̲t̲u̲r̲n̲ : V̲a̲l̲ Γ X  C̲o̲m̲p Γ X

      a̲pp    : Γ ⊢ᵛ X `⇒ Y -> V̲a̲l̲ Γ X -> C̲o̲m̲p Γ Y

  toComp :  C̲o̲m̲p Γ X  Γ ⊢ᶜ X
  toComp (r̲e̲t̲u̲r̲n̲ M) = return (toVal M)
  toComp (a̲pp M N) = app M (toVal N)

  wk-c̲o̲m̲p : Wk Γ Δ  C̲o̲m̲p Δ X  C̲o̲m̲p Γ X
  wk-c̲o̲m̲p π (r̲e̲t̲u̲r̲n̲ M) = r̲e̲t̲u̲r̲n̲ (wk-v̲a̲l̲ π M)
  wk-c̲o̲m̲p π (a̲pp M N) = a̲pp (wk-val π M) (wk-v̲a̲l̲ π N)

  data Env where

             :  Env ε

      _﹐_     :  Env Γ  (M : V̲a̲l̲ Γ X)  Env (Γ  X)

      _﹐﹝_╎_﹞ :  (γ : Env Γ)  (W : Γ ⊢ᶜ X)  (cs : CompStack Δ X)  {π : Wk Γ Δ}  {wk≡ :  π ⟧ʷ  γ ⟧ᴱ   topCsEnv cs ⟧ᴱ}  Env (Γ  `V)

  variable
      γ  : Env Γ
      γ' : Env Γ'
      γ'' : Env Γ''

  topCsEnv  = 
  topCsEnv (W  γ ⦂⦂ cs) = γ

  ⟦_⟧ᴷ : (cs : CompStack Δ Y)   Y   R
  ⟦_⟧ᴷ cs y =  cs ⟧ᶜˢ (η y) k₀

    ⟧ᴱ = tt
   E  M ⟧ᴱ =  E ⟧ᴱ ,  toVal M ⟧ᵛ  E ⟧ᴱ
   E ﹐﹝ W  cs  ⟧ᴱ =  E ⟧ᴱ ,  W ⟧ᶜ  E ⟧ᴱ  cs ⟧ᴷ

    ⟧ᶜˢ = idf
   W₁  γ₁ ⦂⦂ tail ⟧ᶜˢ = < const  γ₁ ⟧ᴱ , idf >  τ  ( W₁ ⟧ᶜ )   tail ⟧ᶜˢ



  -- Lookup Machine
  ------------------------------------------------------------------------------

  data LookupState : Ty  Set where

      ⟨_∥_⟩   :  (i : Γ  X)  Env Γ  LookupState X

  ⟦_⟧ᴸ : (S : LookupState X)   X 
    i  E  ⟧ᴸ =  i ⟧ᵐ  E ⟧ᴱ

  lCtx : (S : LookupState X)  Ctx
  lCtx (⟨_∥_⟩ {Γ = Γ} i E)= Γ

  lTCtx : (S : LookupState X)  Ctx
  lTCtx (⟨_∥_⟩ i ) = ε
  lTCtx (⟨_∥_⟩ i (_﹐_ {Γ = Γ} E M)) = Γ
  lTCtx (⟨_∥_⟩ i (_﹐﹝_╎_﹞ {Γ = Γ} E M k)) = Γ

  lEnv : (S : LookupState X)  Env (lCtx S)
  lEnv  i  E  = E

  lTEnv : (S : LookupState X)  Env (lTCtx S)
  lTEnv  i  E  M  = E
  lTEnv  i  E ﹐﹝ M  cs   = E

  data _→ᴸ_ : LookupState X  LookupState X  Set where

      val-h-step    : {E : Env Γ}  {i : Γ  `V}   h   E  (v̲a̲r̲ i)  →ᴸ  i  E 

      val-t-step    : {i : Γ  Y}  {E : Env Γ}  {M : V̲a̲l̲ Γ X}   t i   _﹐_ E M  →ᴸ  i  E 

      comp-t-step   : {i : Γ  Y}  {γ : Env Γ}  {W : Γ ⊢ᶜ X}  {cs : CompStack Δ X}  {π : Wk Γ Δ}  {wk≡ :  π ⟧ʷ  γ ⟧ᴱ   topCsEnv cs ⟧ᴱ}   t i   (_﹐﹝_╎_﹞ γ W cs {π = π} {wk≡ = wk≡})  →ᴸ  i  γ 


  data _→ᴸ*_ : LookupState X  LookupState X  Set where

    _◼ : (S : LookupState X)  S →ᴸ* S

    _→ᴸ⟨_⟩_ : (S : LookupState X)  {S' S'' : LookupState X}  S →ᴸ S'  S' →ᴸ* S''  S →ᴸ* S''


  data LookupHaltingState : LookupState X  Set where

        found-unit : {γ : Env Γ}  LookupHaltingState  h  _﹐_ γ u̲n̲i̲t̲ 

        found-pair : {LHS : V̲a̲l̲ Γ X}  {RHS : V̲a̲l̲ Γ Y}  {γ : Env Γ}  LookupHaltingState  h  _﹐_ γ (pa̲i̲r̲ LHS RHS) 

        found-lam : {W : (Γ  X) ⊢ᶜ Y}  {γ : Env Γ}  LookupHaltingState  h  _﹐_ γ (l̲a̲m̲ W) 

        found-comp : {W : Γ ⊢ᶜ X}  {γ : Env Γ}  {cs : CompStack Δ X}  {π : Wk Γ Δ}  {wk≡ :  π ⟧ʷ  γ ⟧ᴱ   topCsEnv cs ⟧ᴱ}  LookupHaltingState  h  (_﹐﹝_╎_﹞ γ W cs {π = π} {wk≡ = wk≡}) 

  postulate
    extensionality :  {A B : Set} {f g : A  B}
       (∀ (x : A)  f x  g x)
        -----------------------
       f  g

  -- https://stackoverflow.com/questions/56304634/is-functional-extensionality-with-dependent-functions-consistent
  extensionality' :  {A : Set}{B : A  Set}{f g :  a  B a}  (∀ x  f x  g x)  f  g
  extensionality' {A}{B}{f}{g} e =
      H.≅-to-≡ (H.cong  f x  proj₂ (f x)) (H.≡-to-≅ (extensionality λ a  cong (a ,_) (e a))))

  ≤-uniq : {n₁ n₂ : }  (n₁≤n₂ : n₁  n₂)  (n₁≤n₂' : n₁  n₂)  n₁≤n₂  n₁≤n₂'
  ≤-uniq z≤n z≤n = refl
  ≤-uniq (s≤s n₁≤n₂) (s≤s n₁≤n₂') = cong s≤s (≤-uniq n₁≤n₂ n₁≤n₂')

  data  : Set where

  ql :   (A : Set)  A
  ql () b

  wk-prev : Wk (Γ  X) (Δ  Y)  Wk Γ Δ
  wk-prev (wk-cong π) = π
  wk-prev (wk-wk π) = wk-trans π (wk-wk wk-id)

  wk-absurd : Wk Γ (Δ  A)  Wk Δ Γ  
  wk-absurd {Γ = Γ} {Δ = Δ} (wk-cong π) (wk-cong π') = wk-absurd π π'
  wk-absurd {Γ = Γ} {Δ = Δ} (wk-cong π) (wk-wk π') = wk-absurd (wk-trans π' (wk-wk π)) wk-id
  wk-absurd {Γ = Γ} {Δ = Δ} (wk-wk π) (wk-cong π') = wk-absurd π (wk-wk π')
  wk-absurd {Γ = Γ} {Δ = Δ} (wk-wk π) (wk-wk π') = wk-absurd π (wk-wk (wk-prev {X = R₀} (wk-wk π')))

  wk-id-id : {π : Wk Γ Γ}  π  wk-id
  wk-id-id {π = wk-ε} = refl
  wk-id-id {π = wk-cong π} rewrite wk-id-id {π = π} = refl
  wk-id-id {π = wk-wk π} = ql (wk-absurd π wk-id) (wk-wk π  wk-id)

  p-eq-p : suc n  suc m  n  m
  p-eq-p {n = zero} {m = zero} n≡m = refl
  p-eq-p {n = suc n} {m = suc m} refl = refl

  eq-to-ineq : n  m  n  m
  eq-to-ineq {n = zero} {m = zero} refl = z≤n
  eq-to-ineq {n = zero} {m = suc m} ()
  eq-to-ineq {n = suc n} {m = zero} ()
  eq-to-ineq {n = suc n} {m = suc m} refl = s≤s (eq-to-ineq refl)

  --------------------------------------------------------------------

  data LookupSteps : LookupState X  Set where

    steps : {S T : LookupState X}  S →ᴸ* T  (H : LookupHaltingState T)   S ⟧ᴸ   T ⟧ᴸ  (π : Wk (lCtx S) (lTCtx T))  ( π ⟧ʷ  lEnv S ⟧ᴱ   lTEnv T ⟧ᴱ)
             LookupSteps S

  lookup : (i : Γ  X)  (γ : Env Γ)  LookupSteps {X = X}  i  γ 
  lookup h (γ  l̲a̲m̲ W) = steps ( h  _﹐_ γ (l̲a̲m̲ W)  ) found-lam refl (wk-wk wk-id) refl
  lookup h (γ  pa̲i̲r̲ LHS RHS) = steps ( h  _﹐_ γ (pa̲i̲r̲ LHS RHS)  ) found-pair refl (wk-wk wk-id) refl
  lookup h (γ  u̲n̲i̲t̲) = steps ( h  _﹐_ γ (u̲n̲i̲t̲)  ) found-unit refl (wk-wk wk-id) refl
  lookup h (γ  v̲a̲r̲ i) with lookup i γ
  ... | steps {T = T} i>>T HT i≡T WK w≡γ = steps (_ →ᴸ⟨ val-h-step  i>>T) HT i≡T (wk-wk WK) w≡γ
  lookup h ((γ ﹐﹝ W  cs  ) {π = π} {wk≡ = wk≡}) =
      steps ( h  γ ﹐﹝ W  cs   ) found-comp refl (wk-wk wk-id) refl
  lookup (t i) (γ  M) with lookup i γ
  ... | steps {T = T} i>>T HT i≡T WK w≡γ = steps (_ →ᴸ⟨ val-t-step  i>>T) HT i≡T (wk-wk WK) w≡γ
  lookup (t i) (γ ﹐﹝ W  cs ) with lookup i γ
  ... | steps {T = T} i>>T HT i≡T WK w≡γ =
      steps (_ →ᴸ⟨ comp-t-step  i>>T) HT i≡T (wk-wk WK) w≡γ

  -- Value Machine
  ------------------------------------------------------------------------------

  data BottomTypeEqualsNextType : IsEmpty  Ty  Ty  Set where

      🗆 : BottomTypeEqualsNextType empty X X

      🗇 : BottomTypeEqualsNextType non-empty X Y

  data PartialTerm : (Γ : Ctx)  (X : Ty)  Set where

      ⭭_ : V̲a̲l̲ Γ X  PartialTerm Γ X

      ⇡_ : (M : Γ ⊢ᵛ X)  PartialTerm Γ X

      ⇡ᴹ : (M : Γ ⊢ᵛ X  Y)  (N : (Γ  X  Y) ⊢ᵛ Z)  PartialTerm Γ Z

      ⇡ᴸ : (LHS : Γ ⊢ᵛ X)  (RHS : Γ ⊢ᵛ Y)  PartialTerm Γ (X  Y)

      ⇡ᴿ  : (LHS : V̲a̲l̲ Γ X)  (RHS : Γ ⊢ᵛ Y)  PartialTerm Γ (X  Y)


  data ValStack : IsEmpty  Ty  Set where

       : ValStack empty T◾

      _⊲_∷_ : PartialTerm Γ X  (γ : Env Γ)  (tail : ValStack b T◾)  { : BottomTypeEqualsNextType b X T◾}  ValStack non-empty T◾


  data ValState : Ty  Set where

      ∘_ : ValStack non-empty T◾  ValState T◾

      ∙_ : ValStack non-empty T◾  ValState T◾

  data _→ᵛ_ : ValState T◾  ValState T◾  Set where

      ∘var-c  :    {i : Γ  `V}  {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b `V T◾}
                ----------------------------------------------------------------
                    (( var i  γ  tail) { = }) →ᵛ  (( v̲a̲r̲ i  γ  tail) { = })

      ∘var    :    {i : Γ  X}  {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b X T◾}
                   {M : V̲a̲l̲ Γ' X}
                   ( i  γ  →ᴸ*  h  _﹐_ γ' M )  (πᵥ : Wk Γ Γ')
                ----------------------------------------------------------------
                    (( var i  γ  tail) { = }) →ᵛ  (( (wk-v̲a̲l̲ πᵥ M)  γ  tail) { = })


      ∘lam   :  {M : (Γ  X) ⊢ᶜ Y}  {γ  : Env Γ}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b (X `⇒ Y) T◾}
                ---------------------------------------------------------------------------
                    (( lam M  γ  tail) { = })
                  →ᵛ  (( l̲a̲m̲ M  γ  tail) { = })

      ∘pair  :  {LHS : Γ ⊢ᵛ X}  {RHS : Γ ⊢ᵛ Y}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b (X  Y) T◾}
                ---------------------------------------------------------------------------
                    (( pair LHS RHS  γ  tail) { = })
                  →ᵛ  (( LHS  γ  ((⇡ᴸ LHS RHS  γ  tail) { = })) { = 🗇})

      ∘pm    :  {M : Γ ⊢ᵛ X  Y}  {N : (Γ  X  Y) ⊢ᵛ Z}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b Z T◾}
                ---------------------------------------------------------------------------
                    (( pm M N  γ  tail) { = })
                  →ᵛ  (( M  γ  (⇡ᴹ M N  γ  tail) { = }) { = 🗇})

      ∘unit  :  {γ  : Env Γ}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b `Unit T◾}
                ---------------------------------------------------------------------------
                    (( unit  γ  tail) { = })
                  →ᵛ  (( u̲n̲i̲t̲  γ  tail) { = })

      ∙M∷l   :  {M : V̲a̲l̲ Γ X}  {LHS : Γ' ⊢ᵛ X}  {RHS : Γ' ⊢ᵛ Y}  {π' : Wk Γ Γ'}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b (X  Y) T◾}
                ---------------------------------------------------------------------------
                    (( M  γ  ((⇡ᴸ LHS RHS  γ'  tail) { = })) { = 🗇})
                  →ᵛ  (( wk-val π' RHS  γ  ((⇡ᴿ M (wk-val π' RHS)  γ  tail) { = })) { = 🗇})

      ∙M∷r   :  {M : V̲a̲l̲ Γ Y}  {LHS : V̲a̲l̲ Γ' X}  {RHS : Γ' ⊢ᵛ Y} {π' : Wk Γ Γ'}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b (X  Y) T◾}
                ---------------------------------------------------------------------------
                    (( M  γ  ((⇡ᴿ LHS RHS  γ'  tail) { = })) { = 🗇})
                  →ᵛ  (( pa̲i̲r̲ (wk-v̲a̲l̲ π' LHS) M  γ  tail) { = })

      ∙pair∷pm  :  {LHS : V̲a̲l̲ Γ X}  {RHS : V̲a̲l̲ Γ Y}  {M : Γ' ⊢ᵛ X  Y}  {N : (Γ'  X  Y) ⊢ᵛ Z}
               {π' : Wk Γ Γ'}
               {tail : ValStack b T◾}  { : BottomTypeEqualsNextType b Z T◾}
                ---------------------------------------------------------------------------
                    (( pa̲i̲r̲ LHS RHS  γ  ((⇡ᴹ M N  γ'  tail) { = })) { = 🗇})
                  →ᵛ   (( (wk-val (wk-cong (wk-cong π')) N)  γ  LHS  (wk-v̲a̲l̲ (wk-wk wk-id) RHS)  tail) { = })


  data _↠ᵛ_ : ValState T◾  ValState T◾  Set where

    _→ᵛ⟨_⟩. : (S : ValState T◾)  {S' : ValState T◾}  (laststep : S →ᵛ S')  S ↠ᵛ S'

    _→ᵛ⟨_⟩_ : (S : ValState T◾)  {S' S'' : ValState T◾}  S →ᵛ S'  S' ↠ᵛ S''  S ↠ᵛ S''

  _⨾_ : {F S T : ValState T◾}  (F ↠ᵛ S)  (S ↠ᵛ T)  (F ↠ᵛ T)
  _⨾_ (F →ᵛ⟨ F>S ⟩.) S>>T = F →ᵛ⟨ F>S  S>>T
  _⨾_ (F →ᵛ⟨ F>S₁  S₁>>S₂) S₂>>T = F →ᵛ⟨ F>S₁  (S₁>>S₂  S₂>>T)

  _⧺_ : ValStack b T◾  ValStack non-empty T◾'  ValStack non-empty T◾'
    lower = lower
  (M  γ  upper)  lower = (M  γ  (upper  lower)) { = 🗇}

  _⧻_ : (upper : ValState T◾)  ValStack non-empty T◾'  ValState T◾'
  ( upper)  lower =  (upper  lower)
  ( upper)  lower =  (upper  lower)

  ⟨_⟩⧻_ : {from : ValState T◾}  {to : ValState T◾}  (F>T : from →ᵛ to)  (tail : ValStack non-empty T◾')  (from  tail) →ᵛ (to  tail)
   ∘var-c ⟩⧻ tail = ∘var-c
   ∘var T>>U π ⟩⧻ tail = ∘var T>>U π
   ∘lam ⟩⧻ tail = ∘lam
   ∘pair ⟩⧻ tail = ∘pair
   ∘pm ⟩⧻ tail = ∘pm
   ∘unit ⟩⧻ tail = ∘unit
   ∙pair∷pm ⟩⧻ tail = ∙pair∷pm
   ∙M∷l ⟩⧻ tail = ∙M∷l
   ∙M∷r ⟩⧻ tail = ∙M∷r

  ⟪_⟫⧻_ : {from : ValState T◾}  {to : ValState T◾}  (F>T : from ↠ᵛ to)  (tail : ValStack non-empty T◾')  (from  tail) ↠ᵛ (to  tail)
   _ →ᵛ⟨ F>T ⟩. ⟫⧻ tail =  _ →ᵛ⟨  F>T ⟩⧻ tail ⟩.
   _ →ᵛ⟨ F>T  F>>T ⟫⧻ tail =   _ →ᵛ⟨  F>T ⟩⧻ tail  ( F>>T ⟫⧻ tail)

  ⟦_⟧ᵛˢ : (S : ValStack non-empty T◾)   T◾ 
   ( x  γ  ) { = 🗆} ⟧ᵛˢ =  toVal x ⟧ᵛ  γ ⟧ᴱ
   ( M  γ  ) { = 🗆} ⟧ᵛˢ =  M ⟧ᵛ  γ ⟧ᴱ
   (⇡ᴹ M N  γ  ) { = 🗆} ⟧ᵛˢ =  pm M N ⟧ᵛ  γ ⟧ᴱ
   (⇡ᴸ LHS RHS  γ  ) { = 🗆} ⟧ᵛˢ =  pair LHS RHS ⟧ᵛ  γ ⟧ᴱ
   (⇡ᴿ LHS RHS  γ  ) { = 🗆} ⟧ᵛˢ =  pair (toVal LHS) RHS ⟧ᵛ  γ ⟧ᴱ
   ( x  γ  ((x₁  γ₁  S) { = })) { = 🗇} ⟧ᵛˢ =  (x₁  γ₁  S) { = } ⟧ᵛˢ
   ( M  γ  ((x₁  γ₁  S) { = })) { = 🗇} ⟧ᵛˢ =  (x₁  γ₁  S) { = } ⟧ᵛˢ
   (⇡ᴹ M N  γ  ((x₁  γ₁  S) { = })) { = 🗇} ⟧ᵛˢ =  (x₁  γ₁  S) { = } ⟧ᵛˢ
   (⇡ᴸ LHS RHS  γ  ((x₁  γ₁  S) { = })) { = 🗇} ⟧ᵛˢ =  (x₁  γ₁  S) { = } ⟧ᵛˢ
   (⇡ᴿ LHS RHS  γ  ((x₁  γ₁  S) { = })) { = 🗇} ⟧ᵛˢ =  (x₁  γ₁  S) { = } ⟧ᵛˢ


  ⟦_⟧ᵛꟴ : (S : ValState T◾)   T◾ 
    tail ⟧ᵛꟴ =  tail ⟧ᵛˢ
    tail ⟧ᵛꟴ =  tail ⟧ᵛˢ

  topStackCtx : (S : ValStack non-empty T◾)  Ctx
  topStackCtx (_⊲_∷_ {Γ = Γ} _ _ _) = Γ

  topCtx : ValState T◾  Ctx
  topCtx ( S) = topStackCtx S
  topCtx ( S) = topStackCtx S

  topStackEnv : (S : ValStack non-empty T◾)  Env (topStackCtx S)
  topStackEnv (_⊲_∷_ _ γ _) = γ

  topEnv : (S : ValState T◾)  Env (topCtx S)
  topEnv ( S) = topStackEnv S
  topEnv ( S) = topStackEnv S

  data ValHaltingState : ValState T◾  Set where

      ∙_⊲_■ : (M : V̲a̲l̲ Γ X)  (γ : Env Γ)  ValHaltingState ( (( M  γ  ) { = 🗆}))

  botStackCtx : ValStack non-empty T◾  Ctx
  botStackCtx ((_⊲_∷_) {Γ = Γ} _ _ ) = Γ
  botStackCtx ((x  γ  ((x₁  γ₁  xs) { = ↥'})) { = }) = botStackCtx ((x₁  γ₁  xs) { = ↥'})

  botCtx : ValState T◾  Ctx
  botCtx ( S) = botStackCtx S
  botCtx ( S) = botStackCtx S

  botStackEnv : (S : ValStack non-empty T◾)  Env (botStackCtx S)
  botStackEnv ((_⊲_∷_) {Γ = Γ} _ γ ) = γ
  botStackEnv ((x  γ  ((x₁  γ₁  xs) { = ↥'})) { = }) = botStackEnv ((x₁  γ₁  xs) { = ↥'})

  botEnv : (S : ValState T◾)  Env (botCtx S)
  botEnv ( S) = botStackEnv S
  botEnv ( S) = botStackEnv S

  botStackTerm : (S : ValStack non-empty T◾)  PartialTerm (botStackCtx S) (T◾)
  botStackTerm ((_⊲_∷_) {Γ = Γ} M γ  { = 🗆}) = M
  botStackTerm ((x  γ  ((x₁  γ₁  xs) { = ↥'})) { = }) = botStackTerm ((x₁  γ₁  xs) { = ↥'})

  data ValSteps : ValState T◾  Set where

    steps : {S T : ValState T◾}  S ↠ᵛ T  ValHaltingState T   S ⟧ᵛꟴ   T ⟧ᵛꟴ  (π : Wk (botCtx T) (botCtx S))  ( π ⟧ʷ  botEnv T ⟧ᴱ   botEnv S ⟧ᴱ)
             ValSteps S


  val-eval-rec : (M : Γ' ⊢ᵛ X)  (γ : Env Γ)  (π : Wk Γ Γ')  ValSteps {T◾ = X} ( (( (wk-val π M)  γ  ) { = 🗆}))

  val-eval-rec {X = `V} (var {A = .`V} i) γ π = steps (_ →ᵛ⟨ ∘var-c ⟩.) ( v̲a̲r̲ (wk-mem π i)  γ ) refl wk-id refl

  val-eval-rec {X = `Unit} (var {A = .`Unit} i) γ π with lookup (wk-mem π i) γ
  ... | steps i>>T found-unit i≡T π₁ w≡γ = steps (_ →ᵛ⟨ ∘var i>>T π₁ ⟩.) ( u̲n̲i̲t̲  γ ) refl wk-id refl

  val-eval-rec {X = X  X₁} (var {A = .(X  X₁)} i) γ π with lookup (wk-mem π i) γ
  ... | steps i>>T (found-pair {LHS = LHS} {RHS = RHS} {γ = γ₁}) i≡T π₁ w≡γ =

            steps

            (_ →ᵛ⟨ ∘var i>>T π₁ ⟩.)

            ( pa̲i̲r̲ (wk-v̲a̲l̲ π₁ LHS) (wk-v̲a̲l̲ π₁ RHS)  γ )

            ( wk-mem π i ⟧ᵐ  γ ⟧ᴱ
            ≡⟨ i≡T 
            (<  toVal LHS ⟧ᵛ ,  toVal RHS ⟧ᵛ >  γ₁ ⟧ᴱ)
            ≡⟨ cong  x  <  toVal LHS ⟧ᵛ ,  toVal RHS ⟧ᵛ > x) (sym w≡γ) 
            (<  toVal LHS ⟧ᵛ ,  toVal RHS ⟧ᵛ > ( π₁ ⟧ʷ  γ ⟧ᴱ))
            ≡⟨ refl 
            ( wk-val π₁ (toVal LHS) ⟧ᵛ  γ ⟧ᴱ ,  wk-val π₁ (toVal RHS) ⟧ᵛ  γ ⟧ᴱ)
            ≡⟨ cong  x  ( x ⟧ᵛ  γ ⟧ᴱ ,  wk-val π₁ (toVal RHS) ⟧ᵛ  γ ⟧ᴱ)) (wk-comm {M = LHS} {π = π₁}) 
            ( toVal (wk-v̲a̲l̲ π₁ LHS) ⟧ᵛ  γ ⟧ᴱ ,  wk-val π₁ (toVal RHS) ⟧ᵛ  γ ⟧ᴱ)
            ≡⟨ cong  x  ( toVal (wk-v̲a̲l̲ π₁ LHS) ⟧ᵛ  γ ⟧ᴱ ,  x ⟧ᵛ  γ ⟧ᴱ)) (wk-comm {M = RHS} {π = π₁}) 
            ( toVal (wk-v̲a̲l̲ π₁ LHS) ⟧ᵛ  γ ⟧ᴱ ,  toVal (wk-v̲a̲l̲ π₁ RHS) ⟧ᵛ  γ ⟧ᴱ)
            ≡⟨ refl 
            (<  toVal (wk-v̲a̲l̲ π₁ LHS) ⟧ᵛ ,  toVal (wk-v̲a̲l̲ π₁ RHS) ⟧ᵛ >  γ ⟧ᴱ) )

            wk-id

            refl

  val-eval-rec {X = X `⇒ X₁} (var {A = .(X `⇒ X₁)} i) γ π with lookup (wk-mem π i) γ

  ... | steps i>>T (found-lam {W = W} {γ = γ₁}) i≡T π₁ w≡γ =

            steps

            (_ →ᵛ⟨ ∘var i>>T π₁ ⟩.)

            ( (wk-v̲a̲l̲ π₁ (l̲a̲m̲ W))  γ )

            ( wk-mem π i ⟧ᵐ  γ ⟧ᴱ
              ≡⟨ i≡T 
            ((λ y   W ⟧ᶜ ( γ₁ ⟧ᴱ , y) ))
              ≡⟨ cong  x   y   W ⟧ᶜ (x , y) )) (sym w≡γ) 
             y   W ⟧ᶜ ( π₁ ⟧ʷ  γ ⟧ᴱ , y) )
              ≡⟨ refl 
            (curry (<  r  proj₁ r)   π₁ ⟧ʷ ,  r  proj₂ r) >   W ⟧ᶜ))  γ ⟧ᴱ )

            wk-id

            refl

  val-eval-rec (lam W) γ π = steps (  (wk-val π (lam W))  γ   →ᵛ⟨ ∘lam ⟩.) ( l̲a̲m̲ (wk-comp (wk-cong π) W)  γ ) refl wk-id refl

  val-eval-rec unit γ π = steps (_ →ᵛ⟨ ∘unit ⟩.) ( u̲n̲i̲t̲  γ ) refl wk-id refl

  val-eval-rec (pair {A = X} {B = Y} LHS RHS) γ π with val-eval-rec {X = X} LHS γ π
  ... | steps {T =  (⭭_ {X = X} LT  γ₁  ) { = 🗆}} L>T ∙LT L≡T πᴸ wk≡ᴸ with  val-eval-rec {X = Y} RHS γ₁ (wk-trans πᴸ π)
  ...      | steps {T =  (⭭_ {X = Y} RT  γ₂  ) { = 🗆}} R>T ∙RT R≡T πᴿ wk≡ᴿ rewrite sym (wk-val-trans RHS πᴸ π) =

            steps

              (
                (wk-val π (pair LHS RHS))  γ   →ᵛ⟨ ∘pair ⟩. 
              ( L>T ⟫⧻ (⇡ᴸ (wk-val π LHS) (wk-val π RHS)  γ  )) 
              (  LT  γ₁  ⇡ᴸ (wk-val π LHS) (wk-val π RHS)  γ  ) →ᵛ⟨ ∙M∷l ⟩. 
              ( R>T ⟫⧻ (⇡ᴿ LT (wk-val πᴸ (wk-val π RHS))  γ₁  )) 
              (  RT  γ₂  ⇡ᴿ LT (wk-val πᴸ (wk-val π RHS))  γ₁  ) →ᵛ⟨ ∙M∷r ⟩.
              )

               pa̲i̲r̲ (wk-v̲a̲l̲ πᴿ LT) RT  γ₂ 

              (  wk-val π (pair LHS RHS) ⟧ᵛ  γ ⟧ᴱ
              ≡⟨ refl 
                ( LHS ⟧ᵛ ( π ⟧ʷ  γ ⟧ᴱ) ,  RHS ⟧ᵛ ( π ⟧ʷ  γ ⟧ᴱ))
              ≡⟨ cong  y  ( LHS ⟧ᵛ ( π ⟧ʷ  γ ⟧ᴱ) ,  RHS ⟧ᵛ ( π ⟧ʷ y))) (sym wk≡ᴸ) 
                ( LHS ⟧ᵛ ( π ⟧ʷ  γ ⟧ᴱ) ,  RHS ⟧ᵛ ( π ⟧ʷ ( πᴸ ⟧ʷ  γ₁ ⟧ᴱ)))
              ≡⟨ cong  y  ( LHS ⟧ᵛ ( π ⟧ʷ  γ ⟧ᴱ) ,  RHS ⟧ᵛ y)) (wk-sem-trans πᴸ π  γ₁ ⟧ᴱ) 
                ( LHS ⟧ᵛ ( π ⟧ʷ  γ ⟧ᴱ) ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))
              ≡⟨ cong  y  (y ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))) L≡T 
                ( toVal LT ⟧ᵛ  γ₁ ⟧ᴱ ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))
              ≡⟨ cong  y  ( toVal LT ⟧ᵛ y ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))) (sym wk≡ᴿ) 
                ( toVal LT ⟧ᵛ ( πᴿ ⟧ʷ  γ₂ ⟧ᴱ) ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))
              ≡⟨ refl 
                ( wk-val πᴿ (toVal LT) ⟧ᵛ  γ₂ ⟧ᴱ ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))
              ≡⟨ cong  y  ( y ⟧ᵛ  γ₂ ⟧ᴱ  ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))) (wk-comm {M = LT} {π = πᴿ}) 
                ( toVal (wk-v̲a̲l̲ πᴿ LT) ⟧ᵛ  γ₂ ⟧ᴱ ,  RHS ⟧ᵛ ( wk-trans πᴸ π ⟧ʷ  γ₁ ⟧ᴱ))
              ≡⟨ cong  y  ( toVal (wk-v̲a̲l̲ πᴿ LT) ⟧ᵛ  γ₂ ⟧ᴱ , y)) R≡T 
                ( toVal (wk-v̲a̲l̲ πᴿ LT) ⟧ᵛ  γ₂ ⟧ᴱ ,  toVal RT ⟧ᵛ  γ₂ ⟧ᴱ)
              ≡⟨ refl 
                 pair (toVal (wk-v̲a̲l̲ πᴿ LT)) (toVal RT) ⟧ᵛ  γ₂ ⟧ᴱ
              ≡⟨ refl 
                 toVal (pa̲i̲r̲ (wk-v̲a̲l̲ πᴿ LT) RT) ⟧ᵛ  γ₂ ⟧ᴱ
              ≡⟨ refl 
                  ( pa̲i̲r̲ (wk-v̲a̲l̲ πᴿ LT) RT  γ₂  ) { = 🗆} ⟧ᵛꟴ  )

              (wk-trans πᴿ πᴸ)

              (  wk-trans πᴿ πᴸ ⟧ʷ  γ₂ ⟧ᴱ
              ≡⟨ sym (wk-sem-trans πᴿ πᴸ  γ₂ ⟧ᴱ) 
                 πᴸ ⟧ʷ ( πᴿ ⟧ʷ  γ₂ ⟧ᴱ)
              ≡⟨ cong  y   πᴸ ⟧ʷ y) wk≡ᴿ 
                 πᴸ ⟧ʷ  γ₁ ⟧ᴱ
              ≡⟨ wk≡ᴸ 
                 γ ⟧ᴱ )


  val-eval-rec {Γ = Γ} (pm {A = A} {B = B} M N) γ π with val-eval-rec M γ π
  ... | steps {S = S} M>T  pa̲i̲r̲ LHS RHS  γ₁  M≡T π₁ wk≡₁ with val-eval-rec N (_﹐_ (_﹐_ γ₁ LHS) (wk-v̲a̲l̲ (wk-wk wk-id) RHS)) ((wk-cong (wk-cong (wk-trans π₁ π)))) | (wk-val-trans N (wk-cong (wk-cong π₁)) (wk-cong (wk-cong π)))
  ...    | steps {T = T} N>T ∙T N≡T π₂ wk≡₂ | eq with N>T
  ...      | N>T' rewrite sym eq =

        steps
          (
            (  pm (wk-val π M) (wk-val (wk-cong (wk-cong π)) N)  γ  ) →ᵛ⟨ ∘pm ⟩. 
            ( M>T ⟫⧻ (⇡ᴹ (wk-val π M) (wk-val (wk-cong (wk-cong π)) N)  γ  )) 
            (  pa̲i̲r̲ LHS RHS  γ₁  ⇡ᴹ (wk-val π M) (wk-val (wk-cong (wk-cong π)) N)  γ  ) →ᵛ⟨ ∙pair∷pm ⟩. 
            N>T'
          )

          ∙T

          (   wk-val π (pm M N) ⟧ᵛ  γ ⟧ᴱ
            ≡⟨ refl 
               pm (wk-val π M) (wk-val (wk-cong (wk-cong π)) N) ⟧ᵛ  γ ⟧ᴱ
            ≡⟨ refl 
            (< idf ,  π ⟧ʷ   M ⟧ᵛ >  assocl   wk-val (wk-cong (wk-cong π)) N ⟧ᵛ)  γ ⟧ᴱ
            ≡⟨ refl 
             wk-val (wk-cong (wk-cong π)) N ⟧ᵛ (assocl ( ( γ ⟧ᴱ ,   M ⟧ᵛ  ( π ⟧ʷ  γ ⟧ᴱ))))
            ≡⟨ cong  y   wk-val (wk-cong (wk-cong π)) N ⟧ᵛ (assocl ( ( γ ⟧ᴱ , y   )))) M≡T 
             wk-val (wk-cong (wk-cong π)) N ⟧ᵛ (assocl ( ( γ ⟧ᴱ ,  ( toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ ,  toVal RHS ⟧ᵛ  γ₁ ⟧ᴱ)  )))
            ≡⟨ refl 
               N ⟧ᵛ (( π ⟧ʷ  γ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal RHS ⟧ᵛ  γ₁ ⟧ᴱ)
            ≡⟨ cong   y   N ⟧ᵛ (( π ⟧ʷ y ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal RHS ⟧ᵛ  γ₁ ⟧ᴱ)) (sym wk≡₁) 
               N ⟧ᵛ (( π ⟧ʷ ( π₁ ⟧ʷ  γ₁ ⟧ᴱ) ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal RHS ⟧ᵛ  γ₁ ⟧ᴱ)
            ≡⟨ refl 
               N ⟧ᵛ (( π ⟧ʷ ( π₁ ⟧ʷ  γ₁ ⟧ᴱ) ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  (wk-val (wk-wk wk-id) (toVal RHS)) ⟧ᵛ ( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ))
            ≡⟨ cong  y   N ⟧ᵛ (( π ⟧ʷ ( π₁ ⟧ʷ  γ₁ ⟧ᴱ) ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  y ⟧ᵛ ( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ))) (wk-comm {M = RHS} {π = wk-wk wk-id}) 
               N ⟧ᵛ (( π ⟧ʷ ( π₁ ⟧ʷ  γ₁ ⟧ᴱ) ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal (wk-v̲a̲l̲ (wk-wk wk-id) RHS) ⟧ᵛ ( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ))
            ≡⟨ cong  y   N ⟧ᵛ ((y ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal (wk-v̲a̲l̲ (wk-wk wk-id) RHS) ⟧ᵛ ( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ))  ) (wk-sem-trans π₁ π  γ₁ ⟧ᴱ) 
             N ⟧ᵛ (( wk-trans π₁ π ⟧ʷ  γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal (wk-v̲a̲l̲ (wk-wk wk-id) RHS) ⟧ᵛ ( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ))
            ≡⟨ N≡T 
             T ⟧ᵛꟴ )

          (wk-trans π₂ (wk-wk (wk-wk π₁)))

          (  wk-trans π₂ (wk-wk (wk-wk π₁)) ⟧ʷ  botEnv T ⟧ᴱ
            ≡⟨ sym (wk-sem-trans π₂ (wk-wk (wk-wk π₁))  botEnv T ⟧ᴱ) 
             wk-wk (wk-wk π₁) ⟧ʷ ( π₂ ⟧ʷ  botEnv T ⟧ᴱ)
            ≡⟨ cong  y   wk-wk (wk-wk π₁) ⟧ʷ y) wk≡₂ 
             wk-wk (wk-wk π₁) ⟧ʷ ((( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ) ,  toVal (wk-v̲a̲l̲ (wk-wk wk-id) RHS) ⟧ᵛ ( γ₁ ⟧ᴱ ,  toVal LHS ⟧ᵛ  γ₁ ⟧ᴱ)))
            ≡⟨ refl 
             π₁ ⟧ʷ  γ₁ ⟧ᴱ
            ≡⟨ wk≡₁ 
             γ ⟧ᴱ )

  val-eval : (M : ε ⊢ᵛ X)  ValSteps {T◾ = X} ( (( wk-val wk-id M    ) { = 🗆}))
  val-eval M = val-eval-rec M  wk-id

{-
  -- EXAMPLES
  --------------------------------------------------

  ex1 : ε ⊢ᵛ `Unit
  ex1 = pm (pair unit unit) (var (t h))

  ex2 : ε ⊢ᵛ `Unit `× `Unit
  ex2 = pm (pm (pair (lam {A = `Unit} {B = `Unit} (return (var h))) unit) (pair unit (var (t h)))) (pm (pair unit unit) (pair (var (t h)) (var (t (t (t h))))))

  ---------------------------------------

  -- call agda2-compute-normalised in the hole below
  -- _ : val-eval ex2 ≡ {!val-eval ex2!}
  -- _ = refl

  --------------------------------------------------------------

  -- This is not used anywhere, but shows that the interpretations of environments and computation stacks respect the cps translation of sub

  sub-cps : (M : (Γ ∙ `V) ⊢ᶜ X) → (N : Γ ⊢ᶜ X) → (γ : ⟦ Γ ⟧ˣ ) → (k : ⟦ X ⟧ → R) → ⟦ sub M N ⟧ᶜ γ k ≡ ⟦ M ⟧ᶜ ( γ , ⟦ N ⟧ᶜ γ k ) k
  sub-cps M N γ k = refl

  sub-cps' : (M : (Γ ∙ `V) ⊢ᶜ X) → (N : Γ ⊢ᶜ X) → (γ : Env Γ) → (cs : CompStack Δ X) → (πₓ : Wk Γ Δ) → (wk≡ : ⟦ πₓ ⟧ʷ ⟦ γ ⟧ᴱ ≡ ⟦ topCsEnv cs ⟧ᴱ) → ⟦ sub M N ⟧ᶜ ⟦ γ ⟧ᴱ ⟦ cs ⟧ᴷ ≡ ⟦ M ⟧ᶜ ⟦ (γ ﹐﹝ N ╎ cs ﹞) {π = πₓ} {wk≡ = wk≡} ⟧ᴱ ⟦ cs ⟧ᴷ
  sub-cps' M N γ cs πₓ wk≡ = refl
-}