{-# OPTIONS --safe --without-K #-}
open import Data.Product using (∃; _,_; -,_) renaming (_×_ to _∧_; proj₁ to fst; proj₂ to snd)

open import Relation.Binary.PropositionalEquality using (_≡_; refl; subst)

module Semantics.Clouston.Evaluation.IS4.Properties
  (Ctx' : Set₁)

  (_→̇_ : (P Q : Ctx') → Set) (let infixr 19 _→̇_; _→̇_ = _→̇_)

  (_≈̇_     : {P Q : Ctx'} → (φ ψ : P →̇ Q) → Set) (let infix 18 _≈̇_; _≈̇_ = _≈̇_)
  (≈̇-refl  : ∀ {P Q : Ctx'} {φ : P →̇ Q} → φ ≈̇ φ)
  (≈̇-sym   : ∀ {P Q : Ctx'} {φ ψ : P →̇ Q} → (φ≈̇ψ : φ ≈̇ ψ) → ψ ≈̇ φ)
  (≈̇-trans : ∀ {P Q : Ctx'} {φ ψ ω : P →̇ Q} → (φ≈̇ψ : φ ≈̇ ψ) → (ψ≈̇ω : ψ ≈̇ ω) → φ ≈̇ ω)

  (_∘_      : {P Q R : Ctx'} → (ψ : Q →̇ R) → (φ : P →̇ Q) → (P →̇ R)) (let infixr 19 _∘_; _∘_ = _∘_)
  (∘-pres-≈̇ : ∀ {P Q R : Ctx'} {ψ ψ' : Q →̇ R} {φ φ' : P →̇ Q} (ψ≈̇ψ' : ψ ≈̇ ψ') (φ≈̇φ' : φ ≈̇ φ') → ψ ∘ φ ≈̇ ψ' ∘ φ')
  (∘-assoc  : {P Q R S : Ctx'} → (ω : R →̇ S) → (ψ : Q →̇ R) → (φ : P →̇ Q) → (ω ∘ ψ) ∘ φ ≈̇ ω ∘ ψ ∘ φ)
  (let _[_]' = _∘_)

  (id'[_]         : (P : Ctx') → P →̇ P)
  (id'-unit-left  : ∀ {P : Ctx'} (Q : Ctx') (φ : P →̇ Q) → id'[ Q ] ∘ φ ≈̇ φ)
  (id'-unit-right : ∀ (P : Ctx') {Q : Ctx'} (φ : P →̇ Q) → φ ∘ id'[ P ] ≈̇ φ)

  ([]'     : Ctx')
  (unit'   : {P : Ctx'} → P →̇ []')
  ([]'-eta : ∀ {P : Ctx'} {φ : P →̇ []'} → φ ≈̇ unit')

  (_×'_          : (P Q : Ctx') → Ctx')
  (⟨_,_⟩'        : {R P Q : Ctx'} → (φ : R →̇ P) → (ψ : R →̇ Q) → R →̇ P ×' Q)
  (⟨,⟩'-pres-≈̇   : ∀ {R P Q : Ctx'} {φ φ' : R →̇ P} {ψ ψ' : R →̇ Q} (φ≈̇φ' : φ ≈̇ φ') (ψ≈̇ψ' : ψ ≈̇ ψ') → ⟨ φ , ψ ⟩' ≈̇ ⟨ φ' , ψ' ⟩')
  (π₁'[_]        : {P : Ctx'} → (Q : Ctx') → P ×' Q →̇ P)
  (π₂'[_]        : (P : Ctx') → {Q : Ctx'} → P ×' Q →̇ Q)
  (let fst'[_]_ = λ {R} {P} Q φ → _∘_ {R} {P ×' Q} {P} π₁'[ Q ] φ)
  (let snd'[_]_ = λ {R} P {Q} φ → _∘_ {R} {P ×' Q} {Q} π₂'[ P ] φ)
  (×'-beta-left  : ∀ {R P Q : Ctx'} {φ : R →̇ P} (ψ : R →̇ Q) → π₁'[ Q ] ∘ ⟨ φ , ψ ⟩' ≈̇ φ)
  (×'-beta-right : ∀ {R P Q : Ctx'} (φ : R →̇ P) {ψ : R →̇ Q} → π₂'[ P ] ∘ ⟨ φ , ψ ⟩' ≈̇ ψ)
  (×'-eta        : ∀ {R P Q : Ctx'} {φ : R →̇ P ×' Q} → φ ≈̇ ⟨ fst'[ Q ] φ , snd'[ P ] φ ⟩')
  (⟨,⟩'-nat      : ∀ {R' R P Q : Ctx'} (φ : R →̇ P) (ψ : R →̇ Q) (ω : R' →̇ R) → ⟨ φ , ψ ⟩' ∘ ω ≈̇ ⟨ φ ∘ ω , ψ ∘ ω ⟩')
  (let _×'-map_ = λ {P} {P'} {Q} {Q'} φ ψ → ⟨_,_⟩' {P ×' Q} {P'} {Q'} (φ ∘ π₁'[ Q ]) (ψ ∘ π₂'[ P ]))

  (let Ty' = Ctx')

  (_⇒'_        : (P Q : Ty') → Ty')
  (lam'        : {R P Q : Ty'} → (φ : R ×' P →̇ Q) → R →̇ P ⇒' Q)
  (lam'-pres-≈̇ : ∀ {R P Q : Ty'} {φ φ' : R ×' P →̇ Q} (φ≈̇φ' : φ ≈̇ φ') → lam' φ ≈̇ lam' φ')
  (app'        : {R P Q : Ty'} → (φ : R →̇ P ⇒' Q) → (ψ : R →̇ P) → R →̇ Q)
  (app'-pres-≈̇ : ∀ {R P Q : Ty'} {φ φ' : R →̇ P ⇒' Q} {ψ ψ' : R →̇ P} (φ≈̇φ' : φ ≈̇ φ') (ψ≈̇ψ' : ψ ≈̇ ψ') → app' φ ψ ≈̇ app' φ' ψ')
  (⇒'-beta     : ∀ {R P Q : Ty'} (φ : R ×' P →̇ Q) (ψ : R →̇ P) → app' (lam' φ) ψ ≈̇ φ [ ⟨ id'[ R ] , ψ ⟩' ]')
  (⇒'-eta      : ∀ {R P Q : Ty'} (φ : R →̇ P ⇒' Q) → φ ≈̇ lam' (app' (φ [ π₁'[ P ] ]') π₂'[ R ]))
  (lam'-nat    : ∀ {R' R P Q : Ty'} (φ : R ×' P →̇ Q) (ψ : R' →̇ R) → lam' φ ∘ ψ ≈̇ lam' (φ ∘ ψ ×'-map id'[ P ]))
  (app'-nat    : ∀ {R' R P Q : Ty'} (φ : R →̇ P ⇒' Q) (ψ : R →̇ P) (ω : R' →̇ R) → app' φ ψ ∘ ω ≈̇ app' (φ ∘ ω) (ψ ∘ ω))

  (✦'_              : (P : Ctx') → Ctx')
  (✦'-map_          : {P Q : Ctx'} → (φ : P →̇ Q) → ✦' P →̇ ✦' Q)
  (✦'-map-pres-≈̇    : {P Q : Ctx'} {φ φ' : P →̇ Q} (φ≈̇φ' : φ ≈̇ φ') → ✦'-map φ ≈̇ ✦'-map φ')
  (✦'-map-pres-id'  : {P : Ctx'} → ✦'-map id'[ P ] ≈̇ id'[ ✦' P ])
  (✦'-map-pres-∘    : {P Q R : Ctx'} (ψ : Q →̇ R) (φ : P →̇ Q) → ✦'-map (ψ ∘ φ) ≈̇ ✦'-map ψ ∘ ✦'-map φ)
  (μ'[_]            : (P : Ctx') → ✦' ✦' P →̇ ✦' P)
  (μ'-nat           : ∀ {P Q : Ctx'} (φ : P →̇ Q) → ✦'-map φ ∘ μ'[ P ] ≈̇ μ'[ Q ] ∘ ✦'-map ✦'-map φ)
  (μ'-assoc[_]      : ∀ (P : Ctx') → μ'[ P ] ∘ μ'[ ✦' P ] ≈̇ μ'[ P ] ∘ ✦'-map μ'[ P ])
  (η'[_]            : (P : Ctx') → P →̇ ✦' P)
  (η'-nat           : ∀ {P Q : Ctx'} (φ : P →̇ Q) → ✦'-map φ ∘ η'[ P ] ≈̇ η'[ Q ] ∘ φ)
  (η'-unit-left[_]  : ∀ (P : Ctx') → μ'[ P ] ∘ η'[ ✦' P ] ≈̇ id'[ ✦' P ])
  (η'-unit-right[_] : ∀ (P : Ctx') → μ'[ P ] ∘ ✦'-map η'[ P ] ≈̇ id'[ ✦' P ])

  (□'_          : (P : Ty') → Ty')
  (□'-map_      : {P Q : Ctx'} → (φ : P →̇ Q) → □' P →̇ □' Q)
  (box'         : {P Q : Ty'} → (φ : ✦' P →̇ Q) → P →̇ □' Q)
  (box'-pres-≈̇  : ∀ {P : Ctx'} {Q : Ty'} {φ φ' : ✦' P →̇ Q} (φ≈̇φ' : φ ≈̇ φ') → box' φ ≈̇ box' φ')
  (λ'           : {P Q : Ty'} → (φ : P →̇ □' Q) → ✦' P →̇ Q)
  (λ'-pres-≈̇    : ∀ {P : Ctx'} {Q : Ty'} {φ φ' : P →̇ □' Q} (φ≈̇φ' : φ ≈̇ φ') → λ' φ ≈̇ λ' φ')
  (□'-beta      : ∀ {P : Ctx'} {Q : Ty'} (φ : ✦' P →̇ Q) → λ' (box' φ) ≈̇ φ)
  (□'-eta       : ∀ {P : Ctx'} {Q : Ty'} (φ : P →̇ □' Q) → φ ≈̇ box' (λ' φ))
  (box'-nat-dom : ∀ {P' P : Ctx'} {Q : Ty'} (φ : ✦' P →̇ Q) (φ' : P' →̇ P) → box' (φ ∘ ✦'-map φ') ≈̇ box' φ ∘ φ')
  (λ'-nat-dom   : ∀ {P' P : Ctx'} {Q : Ty'} (φ : P →̇ □' Q) (φ' : P' →̇ P) → λ' (φ ∘ φ') ≈̇ λ' φ ∘ ✦'-map φ')

  (N : Ty')
  where

open import Level using (0ℓ)

open import Relation.Binary using (IsEquivalence; Setoid)

import Relation.Binary.Reasoning.Setoid as EqReasoning

open import IS4.Term.Base
open import IS4.Term.Conversion
open import IS4.Term.Reduction

open import Semantics.Clouston.Evaluation.IS4.Base
    Ctx' _→̇_ _≈̇_ ≈̇-refl ≈̇-sym ≈̇-trans _∘_ id'[_]
    []' unit' _×'_ ⟨_,_⟩' π₁'[_] π₂'[_]
    _⇒'_ lam' app'
    ✦'_ ✦'-map_ μ'[_] η'[_]
    □'_ box' λ'
  renaming (module Eval to CloustonEvaluationIS4BaseEval)

open CloustonEvaluationIS4BaseEval N

open import Semantics.Clouston.Evaluation.IML.Properties
    Ctx' _→̇_ _≈̇_ ≈̇-refl ≈̇-sym ≈̇-trans _∘_ ∘-pres-≈̇ ∘-assoc id'[_] id'-unit-left id'-unit-right
    []' unit' []'-eta _×'_ ⟨_,_⟩' ⟨,⟩'-pres-≈̇ π₁'[_] π₂'[_] ×'-beta-left ×'-beta-right ×'-eta ⟨,⟩'-nat
    _⇒'_ lam'  lam'-pres-≈̇ app' app'-pres-≈̇ ⇒'-beta ⇒'-eta lam'-nat app'-nat
    ✦'_ ✦'-map_ ✦'-map-pres-≈̇ ✦'-map-pres-id' ✦'-map-pres-∘
    □'_ □'-map_ box' box'-pres-≈̇ λ' λ'-pres-≈̇ □'-beta □'-eta box'-nat-dom λ'-nat-dom
    N

abstract
  evalAcc-pres-id : ∀ (Γ : Ctx) → evalAcc new[ Γ ] ≈̇ id'[ ✦' evalCtx Γ ]
  evalAcc-pres-id Γ = η'-unit-right[ evalCtx Γ ]

module _ {Δ Γ : Ctx} where
  abstract
    evalAcc-pres-∘ : ∀ (e : CExt Δ Γ Γ') (e' : CExt Θ Δ Δ') → evalAcc (extRAssoc e e') ≈̇ μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc e) ∘ evalAcc e'
    evalAcc-pres-∘ {Θ = Δ} e nil = let open EqReasoning (Sub'-setoid Δ (Γ #)) in begin
      evalAcc (extRAssoc e (nil {Γ = Δ}))
        ≡⟨⟩
      evalAcc e
        ≈˘⟨ id'-unit-left (✦' evalCtx Γ) (evalAcc e) ⟩
      id'[ ✦' evalCtx Γ ] ∘ evalAcc e
        ≈˘⟨ ∘-pres-≈̇-left η'-unit-left[ evalCtx Γ ] (evalAcc e) ⟩
      (μ'[ evalCtx Γ ] ∘ η'[ ✦' evalCtx Γ ]) ∘ evalAcc e
        ≈⟨ ∘-assoc μ'[ evalCtx Γ ] η'[ ✦' evalCtx Γ ] (evalAcc e) ⟩
      μ'[ evalCtx Γ ] ∘ η'[ ✦' evalCtx Γ ] ∘ evalAcc e
        ≈˘⟨ ∘-pres-≈̇-right μ'[ evalCtx Γ ] (η'-nat (evalAcc e)) ⟩
      μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc e) ∘ evalAcc (nil {Γ = Δ})
        ∎
    evalAcc-pres-∘ {Θ = Θ `, a} e (ext {a = a} e') = let open EqReasoning (Sub'-setoid (Θ `, a) (Γ #)) in begin
      evalAcc (extRAssoc e (ext[ a ] e'))
        ≡⟨⟩
      evalAcc (ext[ a ] (extRAssoc e e'))
        ≡⟨⟩
      evalAcc (extRAssoc e e') ∘ π₁'[ evalCtx Θ ][ evalTy a ]
        ≈⟨ ∘-pres-≈̇-left (evalAcc-pres-∘ e e') π₁'[ evalCtx Θ ][ evalTy a ] ⟩
      (μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc e) ∘ evalAcc e') ∘ π₁'[ evalCtx Θ ][ evalTy a ]
        ≈⟨ ∘-assoc μ'[ evalCtx Γ ] (✦'-map (evalAcc e) ∘ evalAcc e') π₁'[ evalCtx Θ ][ evalTy a ] ⟩
      μ'[ evalCtx Γ ] ∘ (✦'-map (evalAcc e) ∘ evalAcc e') ∘ π₁'[ evalCtx Θ ][ evalTy a ]
        ≈⟨ ∘-pres-≈̇-right μ'[ evalCtx Γ ] (∘-assoc (✦'-map (evalAcc e)) (evalAcc e') π₁'[ evalCtx Θ ][ evalTy a ]) ⟩
      μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc e) ∘ evalAcc (ext[ a ] e')
        ∎
    evalAcc-pres-∘ {Θ = Θ #} e (ext#- e') = let open EqReasoning (Sub'-setoid (Θ #) (Γ #)) in begin
      evalAcc (extRAssoc e (ext#- e'))
        ≡⟨⟩
      evalAcc (ext#- (extRAssoc e e'))
        ≡⟨⟩
      μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc (extRAssoc e e'))
        ≈⟨ ∘-pres-≈̇-right μ'[ evalCtx Γ ] (✦'-map-pres-≈̇ (evalAcc-pres-∘ e e')) ⟩
      μ'[ evalCtx Γ ] ∘ ✦'-map (μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc e) ∘ evalAcc e')
        ≈⟨ ∘-pres-≈̇-right μ'[ evalCtx Γ ] (✦'-map-pres-∘ μ'[ evalCtx Γ ] (✦'-map (evalAcc e) ∘ evalAcc e')) ⟩
      μ'[ evalCtx Γ ] ∘ ✦'-map μ'[ evalCtx Γ ] ∘ ✦'-map (✦'-map (evalAcc e) ∘ evalAcc e')
        ≈˘⟨ ∘-assoc μ' (✦'-map μ') (✦'-map (✦'-map (evalAcc e) ∘ evalAcc e')) ⟩
      (μ'[ evalCtx Γ ] ∘ ✦'-map μ'[ evalCtx Γ ]) ∘ ✦'-map (✦'-map (evalAcc e) ∘ evalAcc e')
        ≈⟨ ∘-pres-≈̇ (≈̇-sym μ'-assoc[ evalCtx Γ ]) (✦'-map-pres-∘ (✦'-map (evalAcc e)) (evalAcc e')) ⟩
      (μ'[ evalCtx Γ ] ∘ μ'[ ✦' evalCtx Γ ]) ∘ ✦'-map (✦'-map (evalAcc e)) ∘ ✦'-map (evalAcc e')
        ≈⟨ ∘-assoc μ' μ' (✦'-map ✦'-map (evalAcc e) ∘ ✦'-map (evalAcc e')) ⟩
      μ'[ evalCtx Γ ] ∘ μ'[ ✦' evalCtx Γ ] ∘ ✦'-map (✦'-map (evalAcc e)) ∘ ✦'-map (evalAcc e')
        ≈˘⟨ ∘-pres-≈̇-right μ' (∘-assoc μ' (✦'-map (✦'-map (evalAcc e))) (✦'-map (evalAcc e'))) ⟩
      μ'[ evalCtx Γ ] ∘ (μ'[ ✦' evalCtx Γ ] ∘ ✦'-map (✦'-map (evalAcc e))) ∘ ✦'-map (evalAcc e')
        ≈˘⟨ ∘-pres-≈̇-right μ' (∘-pres-≈̇-left (μ'-nat (evalAcc e)) (✦'-map (evalAcc e'))) ⟩
      μ'[ evalCtx Γ ] ∘ (✦'-map (evalAcc e) ∘ μ'[ evalCtx Δ ]) ∘ ✦'-map (evalAcc e')
        ≈⟨ ∘-pres-≈̇-right μ' (∘-assoc (✦'-map evalAcc e) μ' (✦'-map (evalAcc e'))) ⟩
      μ'[ evalCtx Γ ] ∘ ✦'-map (evalAcc e) ∘ evalAcc (ext#- e')
        ∎

abstract
  evalAcc-pres-wk : ∀ (w : LFExt Γ' Γ ΓR) → evalAcc (upLFExt w) ≈̇ η'[ evalCtx Γ ] ∘ evalWk (LFExtToWk w)
  evalAcc-pres-wk {Γ'} {Γ} nil = let open EqReasoning (Sub'-setoid Γ' (Γ #)) in begin
    evalAcc (upLFExt nil[ Γ ])
      ≡⟨⟩
    η'[ evalCtx Γ ]
      ≈˘⟨ id'-unit-right (evalCtx Γ) η' ⟩
    η'[ evalCtx Γ ] ∘ id'[ evalCtx Γ ]
      ≈˘⟨ ∘-pres-≈̇-right η' (evalWk-pres-id Γ) ⟩
    η'[ evalCtx Γ ] ∘ evalWk idWk[ Γ ]
      ≡⟨⟩
    η'[ evalCtx Γ ] ∘ evalWk (LFExtToWk nil[ Γ ])
      ∎
  evalAcc-pres-wk {Γ' `, a} {Γ} (ext {a = a} w) = let open EqReasoning (Sub'-setoid (Γ' `, a) (Γ #)) in begin
    evalAcc (upLFExt (ext[ a ] w))
      ≡⟨⟩
    evalAcc (ext[ a ] (upLFExt w))
      ≡⟨⟩
    evalAcc (upLFExt w) ∘ π₁'[ evalTy a ]
      ≈⟨ ∘-pres-≈̇-left (evalAcc-pres-wk w) π₁' ⟩
    (η'[ evalCtx Γ ] ∘ evalWk (LFExtToWk w)) ∘ π₁'[ evalTy a ]
      ≈⟨ ∘-assoc η' (evalWk (LFExtToWk w)) π₁' ⟩
    η'[ evalCtx Γ ] ∘ evalWk (LFExtToWk w) ∘ π₁'[ evalTy a ]
      ≡⟨⟩
    η'[ evalCtx Γ ] ∘ evalWk (drop[ a ] (LFExtToWk w))
      ≡⟨⟩
    η'[ evalCtx Γ ] ∘ evalWk (LFExtToWk (ext[ a ] w))
      ∎

module _ {ΓL : Ctx} where
  abstract
    acc-nat' : ∀ (e : CExt Γ ΓL ΓR) (w : Γ ⊆ Δ) → evalAcc e ∘ evalWk w ≈̇ ✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w)
    acc-nat' nil w = ≈̇-sym (η'-nat _)
    acc-nat' (ext {a = a} e) (keep {Δ = Δ} {a} w) = let open EqReasoning (Sub'-setoid (Δ `, a) (ΓL #)) in begin
      evalAcc (ext[ a ] e) ∘ evalWk (keep[ a ] w)
        ≈⟨ ∘-assoc (evalAcc e) π₁' (evalWk (keep[ a ] w)) ⟩
      evalAcc e ∘ π₁'[ evalTy a ] ∘ evalWk (keep[ a ] w)
        ≈⟨ ∘-pres-≈̇-right (evalAcc e) (×'-beta-left (id'[ evalTy a ] ∘ π₂'[ evalCtx Δ ])) ⟩
      evalAcc e ∘ evalWk w ∘ π₁'[ evalTy a ]
        ≈˘⟨ ∘-assoc (evalAcc e) (evalWk w) (π₁'[ evalTy a ]) ⟩
      (evalAcc e ∘ evalWk w) ∘ π₁'[ evalTy a ]
        ≈⟨ ∘-pres-≈̇-left (acc-nat' e w) π₁'[ evalTy a ] ⟩
      (✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w)) ∘ π₁'[ evalTy a ]
        ≈⟨ ∘-assoc (✦'-map (evalWk (factorWk e w))) (evalAcc (factorExt e w)) π₁'[ evalTy a ] ⟩
      ✦'-map (evalWk (factorWk (ext[ a ] e) (keep[ a ] w))) ∘ evalAcc (factorExt (ext[ a ] e) (keep[ a ] w))
        ∎
    acc-nat' e@(ext {a = a} _) (drop {Δ = Δ} {b} w) = let open EqReasoning (Sub'-setoid (Δ `, b) (ΓL #)) in begin
      evalAcc e ∘ evalWk (drop[ b ] w)
        ≈˘⟨ ∘-assoc (evalAcc e) (evalWk w) π₁'[ evalTy b ] ⟩
      (evalAcc e ∘ evalWk w) ∘ π₁'[ evalTy b ]
        ≈⟨ ∘-pres-≈̇-left (acc-nat' e w) π₁'[ evalTy b ] ⟩
      (✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w)) ∘ π₁'[ evalTy b ]
        ≈⟨ ∘-assoc (✦'-map (evalWk (factorWk e w))) (evalAcc (factorExt e w)) π₁'[ evalTy b ] ⟩
      ✦'-map (evalWk (factorWk e (drop[ b ] w))) ∘ evalAcc (factorExt e (drop[ b ] w))
        ∎
    acc-nat' (ext#- e) (keep# {Δ = Δ} w) = let open EqReasoning (Sub'-setoid (Δ #) (ΓL #)) in begin
      evalAcc (ext#- e) ∘ evalWk (keep# w)
        ≈⟨ ∘-assoc μ' (✦'-map (evalAcc e)) (✦'-map (evalWk w)) ⟩
      μ' ∘ ✦'-map (evalAcc e) ∘ ✦'-map (evalWk w)
        ≈˘⟨ ∘-pres-≈̇-right μ' (✦'-map-pres-∘ (evalAcc e) (evalWk w)) ⟩
      μ' ∘ ✦'-map (evalAcc e ∘ evalWk w)
        ≈⟨ ∘-pres-≈̇-right μ' (✦'-map-pres-≈̇ (acc-nat' e w)) ⟩
      μ' ∘ ✦'-map (✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w))
        ≈⟨ ∘-pres-≈̇-right μ' (✦'-map-pres-∘ (✦'-map (evalWk (factorWk e w))) (evalAcc (factorExt e w))) ⟩
      μ' ∘ ✦'-map (✦'-map (evalWk (factorWk e w))) ∘ ✦'-map (evalAcc (factorExt e w))
        ≈˘⟨ ∘-assoc μ' (✦'-map (✦'-map (evalWk (factorWk e w)))) (✦'-map (evalAcc (factorExt e w))) ⟩
      (μ' ∘ ✦'-map (✦'-map (evalWk (factorWk e w)))) ∘ ✦'-map (evalAcc (factorExt e w))
        ≈˘⟨ ∘-pres-≈̇-left (μ'-nat (evalWk (factorWk e w))) (✦'-map (evalAcc (factorExt e w))) ⟩
      (✦'-map (evalWk (factorWk e w)) ∘ μ') ∘ ✦'-map (evalAcc (factorExt e w))
        ≈⟨ ∘-assoc (✦'-map (evalWk (factorWk e w))) μ' (✦'-map (evalAcc (factorExt e w))) ⟩
      ✦'-map (evalWk (factorWk (ext#- e) (keep# w))) ∘ evalAcc (factorExt (ext#- e) (keep# w))
        ∎
    acc-nat' e@(ext#- _) (drop {Δ = Δ} {a} w) = let open EqReasoning (Sub'-setoid (Δ `, a) (ΓL #)) in begin
      evalAcc e ∘ evalWk (drop[ a ] w)
        ≈˘⟨ ∘-assoc (evalAcc e) (evalWk w) π₁'[ evalTy a ] ⟩
      (evalAcc e ∘ evalWk w) ∘ π₁'[ evalTy a ]
        ≈⟨ ∘-pres-≈̇-left (acc-nat' e w) π₁'[ evalTy a ] ⟩
      (✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w)) ∘ π₁'[ evalTy a ]
        ≈⟨ ∘-assoc (✦'-map (evalWk (factorWk e w))) (evalAcc (factorExt e w)) π₁'[ evalTy a ] ⟩
      ✦'-map (evalWk (factorWk e (drop[ a ] w))) ∘ evalAcc (factorExt e (drop[ a ] w))
        ∎

module _ {ΓL : Ctx} where
  abstract
     acc-nat : ∀ (e : CExt Γ ΓL ΓR) (σ : Sub Δ Γ) → evalAcc e ∘ evalSub σ ≈̇ ✦'-map (evalSub (factorSubₛ e σ)) ∘ evalAcc (factorExtₛ e σ)
     acc-nat nil σ = ≈̇-sym (η'-nat (evalSub σ))
     acc-nat {Δ = Δ} (ext {a = a} e) (σ `, t) = let open EqReasoning (Sub'-setoid Δ (ΓL #)) in begin
       evalAcc (ext[ a ] e) ∘ (evalSub (σ `, t))
         ≡⟨⟩
       (evalAcc e ∘ π₁'[ evalTy a ]) ∘ ⟨ evalSub σ , evalTm t ⟩'
         ≈⟨ ∘-assoc (evalAcc e) π₁'[ evalTy a ] ⟨ evalSub σ , evalTm t ⟩' ⟩
       evalAcc e ∘ π₁'[ evalTy a ] ∘ ⟨ evalSub σ , evalTm t ⟩'
         ≈⟨ ∘-pres-≈̇-right (evalAcc e) (×'-beta-left (evalTm t)) ⟩
       evalAcc e ∘ evalSub σ
         ≈⟨ acc-nat e σ ⟩
       ✦'-map (evalSub (factorSubₛ e σ)) ∘ evalAcc (factorExtₛ e σ)
         ≡⟨⟩
       ✦'-map (evalSub (factorSubₛ (ext[ a ] e) (σ `, t))) ∘ evalAcc (factorExtₛ (ext[ a ] e) (σ `, t))
         ∎
     acc-nat {Δ = Δ} (ext#- e) (lock σ e') = let open EqReasoning (Sub'-setoid Δ (ΓL #)) in begin
       evalAcc (ext#- e) ∘ evalSub (lock σ e')
         ≡⟨⟩
       (μ' ∘ ✦'-map (evalAcc e)) ∘ ✦'-map (evalSub σ) ∘ evalAcc e'
         ≈⟨ ∘-assoc μ' (✦'-map (evalAcc e)) (✦'-map (evalSub σ) ∘ evalAcc e') ⟩
       μ' ∘ ✦'-map (evalAcc e) ∘ ✦'-map (evalSub σ) ∘ evalAcc e'
         ≈˘⟨ ∘-pres-≈̇-right μ' (∘-assoc (✦'-map (evalAcc e)) (✦'-map (evalSub σ)) (evalAcc e')) ⟩
       μ' ∘ (✦'-map (evalAcc e) ∘ ✦'-map (evalSub σ)) ∘ evalAcc e'
         ≈˘⟨ ∘-pres-≈̇-right μ' (∘-pres-≈̇-left (✦'-map-pres-∘ (evalAcc e) (evalSub σ)) (evalAcc e')) ⟩
       μ' ∘ ✦'-map (evalAcc e ∘ evalSub σ) ∘ evalAcc e'
         ≈⟨ ∘-pres-≈̇-right μ' (∘-pres-≈̇-left (✦'-map-pres-≈̇ (acc-nat e σ)) (evalAcc e')) ⟩
       μ' ∘ ✦'-map (✦'-map (evalSub (factorSubₛ e σ)) ∘ evalAcc (factorExtₛ e σ)) ∘ evalAcc e'
         ≈⟨ ∘-pres-≈̇-right μ' (∘-pres-≈̇-left (✦'-map-pres-∘ (✦'-map (evalSub (factorSubₛ e σ))) (evalAcc (factorExtₛ e σ))) (evalAcc e')) ⟩
       μ' ∘ (✦'-map ✦'-map (evalSub (factorSubₛ e σ)) ∘ ✦'-map (evalAcc (factorExtₛ e σ))) ∘ evalAcc e'
         ≈⟨ ∘-pres-≈̇-right μ' (∘-assoc (✦'-map ✦'-map (evalSub (factorSubₛ e σ))) (✦'-map (evalAcc (factorExtₛ e σ))) (evalAcc e')) ⟩
       μ' ∘ ✦'-map ✦'-map (evalSub (factorSubₛ e σ)) ∘ ✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e'
         ≈˘⟨ ∘-assoc μ' (✦'-map ✦'-map evalSub (factorSubₛ e σ)) (✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e') ⟩
       (μ' ∘ ✦'-map ✦'-map (evalSub (factorSubₛ e σ))) ∘ ✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e'
         ≈˘⟨ ∘-pres-≈̇-left (μ'-nat (evalSub (factorSubₛ e σ))) (✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e') ⟩
       (✦'-map (evalSub (factorSubₛ e σ)) ∘ μ') ∘ ✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e'
         ≈⟨ ∘-assoc (✦'-map (evalSub (factorSubₛ e σ))) μ' (✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e') ⟩
       ✦'-map (evalSub (factorSubₛ e σ)) ∘ μ' ∘ ✦'-map (evalAcc (factorExtₛ e σ)) ∘ evalAcc e'
         ≈˘⟨ ∘-pres-≈̇-right (✦'-map (evalSub (factorSubₛ e σ))) (evalAcc-pres-∘ (factorExtₛ e σ) e') ⟩
       ✦'-map (evalSub (factorSubₛ (ext#- e) (lock σ e'))) ∘ evalAcc (extRAssoc (factorExtₛ e σ) e')
         ∎

abstract
  evalTm-pres-∘' : ∀ (w : Γ ⊆ Δ) (t : Tm Γ a) → evalTm (wkTm w t) ≈̇ evalTm t [ evalWk w ]'
  evalTm-pres-∘' w (var v) = evalVar-pres-∘ w v
  evalTm-pres-∘' {Δ = Δ} {a} w (lam {a = a'} t) = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (wkTm w (lam t))
      ≈⟨ lam'-pres-≈̇ (evalTm-pres-∘' (keep[ a' ] w) t) ⟩
    lam' (evalTm t ∘ evalWk (keep[ a' ] w))
      ≈˘⟨ lam'-nat (evalTm t) (evalWk w) ⟩
    evalTm (lam t) [ evalWk w ]'
      ∎
  evalTm-pres-∘' {Δ = Δ} {a} w (app t u) = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (wkTm w (app t u))
      ≈⟨ app'-pres-≈̇ (evalTm-pres-∘' w t) (evalTm-pres-∘' w u) ⟩
    app' (evalTm t ∘ evalWk w) (evalTm u ∘ evalWk w)
      ≈˘⟨ app'-nat (evalTm t) (evalTm u) (evalWk w) ⟩
    evalTm (app t u) [ evalWk w ]'
      ∎
  evalTm-pres-∘' {Δ = Δ} {a} w (box t) = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (wkTm w (box t))
      ≈⟨ box'-pres-≈̇ (evalTm-pres-∘' (keep# w) t) ⟩
    box' (evalTm t ∘ evalWk (keep# w))
      ≈⟨ box'-nat-dom (evalTm t) (evalWk w) ⟩
    evalTm (box t) [ evalWk w ]'
      ∎
  evalTm-pres-∘' {Δ = Δ} {a} w (unbox t e) = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (wkTm w (unbox t e))
      ≈⟨ unbox'-pres-≈̇-left (evalTm-pres-∘' (factorWk e w) t) (evalAcc (factorExt e w)) ⟩
    unbox' (evalTm t ∘ evalWk (factorWk e w)) (evalAcc (factorExt e w))
      ≈⟨ unbox'-nat-dom (evalTm t) (evalWk (factorWk e w)) (evalAcc (factorExt e w)) ⟩
    unbox' (evalTm t) (✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w))
      ≈˘⟨ unbox'-pres-≈̇-right (evalTm t) (acc-nat' e w) ⟩
    unbox' (evalTm t) (evalAcc e ∘ evalWk w)
      ≈˘⟨ ∘-assoc (λ' (evalTm t)) (evalAcc e) (evalWk w) ⟩
    evalTm (unbox t e) [ evalWk w ]'
      ∎

abstract
  evalSub-pres-∘' : ∀ (σ : Sub Δ Γ) (w : Δ ⊆ Δ') → evalSub (wkSub w σ) ≈̇ evalSub σ ∘ evalWk w
  evalSub-pres-∘' []         w = ≈̇-sym []'-eta
  evalSub-pres-∘' {Γ = Γ} {Δ'} (σ `, t)   w = let open EqReasoning (Sub'-setoid Δ' Γ) in begin
    evalSub (wkSub w (σ `, t))
      ≈⟨ ⟨,⟩'-pres-≈̇ (evalSub-pres-∘' σ w) (evalTm-pres-∘' w t) ⟩
    ⟨ evalSub σ ∘ evalWk w , evalTm t ∘ evalWk w ⟩'
      ≈˘⟨ ⟨,⟩'-nat (evalSub σ) (evalTm t) (evalWk w) ⟩
    evalSub (σ `, t) ∘ evalWk w
      ∎
  evalSub-pres-∘' {Γ = Γ} {Δ'} (lock σ e) w = let open EqReasoning (Sub'-setoid Δ' Γ) in begin
    evalSub (wkSub w (lock σ e))
      ≈⟨ ∘-pres-≈̇-left (✦'-map-pres-≈̇ (evalSub-pres-∘' σ (factorWk e w))) (evalAcc (factorExt e w)) ⟩
    ✦'-map (evalSub σ ∘ evalWk (factorWk e w)) ∘ evalAcc (factorExt e w)
      ≈⟨ ∘-pres-≈̇-left (✦'-map-pres-∘ (evalSub σ) (evalWk (factorWk e w))) (evalAcc (factorExt e w)) ⟩
    (✦'-map (evalSub σ) ∘ ✦'-map (evalWk (factorWk e w))) ∘ evalAcc (factorExt e w)
      ≈⟨ ∘-assoc (✦'-map (evalSub σ)) (✦'-map (evalWk (factorWk e w))) (evalAcc (factorExt e w)) ⟩
    ✦'-map (evalSub σ) ∘ ✦'-map (evalWk (factorWk e w)) ∘ evalAcc (factorExt e w)
      ≈˘⟨ ∘-pres-≈̇-right (✦'-map (evalSub σ)) (acc-nat' e w) ⟩
    ✦'-map (evalSub σ) ∘ evalAcc e ∘ evalWk w
      ≈˘⟨ ∘-assoc (✦'-map (evalSub σ)) (evalAcc e) (evalWk w) ⟩
    evalSub (lock σ e) ∘ evalWk w
      ∎

abstract
  evalSub-pres-∘-π₁ : ∀ (σ : Sub Δ Γ) (a : Ty) → evalSub (dropₛ {Δ} {Γ} {a} σ) ≈̇ evalSub σ ∘ π₁'[ evalTy a ]
  evalSub-pres-∘-π₁ {Δ} {Γ} σ a = let open EqReasoning (Sub'-setoid (Δ `, a) Γ) in begin
    evalSub (dropₛ {Δ} {Γ} {a} σ)       ≈⟨ evalSub-pres-∘' σ (fresh {Δ} {a}) ⟩
    evalSub σ ∘ evalWk (fresh {Δ} {a})  ≈⟨ ∘-pres-≈̇-right (evalSub σ) (evalWk-pres-π₁ Δ a) ⟩
    evalSub σ ∘ π₁'[ evalTy a ]         ∎

abstract
  evalSub-pres-×-map-id : ∀ (σ : Sub Δ Γ) (a : Ty) → evalSub (keepₛ {Δ} {Γ} {a} σ) ≈̇ evalSub σ ×'-map id'[ evalTy a ]
  evalSub-pres-×-map-id {Δ} {Γ} σ a = let open EqReasoning (Sub'-setoid (Δ `, a) (Γ `, a)) in begin
    evalSub (keepₛ {Δ} {Γ} {a} σ)    ≈⟨ ⟨,⟩'-pres-≈̇ (evalSub-pres-∘-π₁ σ a) (≈̇-sym (id'-unit-left (evalTy a) π₂'[ evalCtx Δ ])) ⟩
    evalSub σ ×'-map id'[ evalTy a ]  ∎

abstract
  evalSub-pres-lock-map : ∀ (σ : Sub Δ Γ) → evalSub (keep#ₛ σ) ≈̇ ✦'-map (evalSub σ)
  evalSub-pres-lock-map {Δ} {Γ} σ = let open EqReasoning (Sub'-setoid (Δ #) (Γ #)) in begin
    evalSub (keep#ₛ σ)                        ≈⟨ ∘-pres-≈̇-right (✦'-map (evalSub σ)) (evalAcc-pres-id Δ) ⟩
    ✦'-map (evalSub σ) ∘ id'[ ✦' evalCtx Δ ]  ≈⟨ id'-unit-right (✦' evalCtx Δ) (✦'-map (evalSub σ)) ⟩
    ✦'-map (evalSub σ)                        ∎

abstract
  evalSub-pres-wk : ∀ (w : Γ ⊆ Γ') → evalSub (embWk w) ≈̇ evalWk w
  evalSub-pres-wk base = []'-eta
  evalSub-pres-wk {Γ} (drop {Δ = Γ'} {a} w) = let open EqReasoning (Sub'-setoid (Γ' `, a) Γ) in begin
    evalSub (embWk (drop[ a ] w))                ≈⟨ evalSub-pres-∘' (embWk w) (fresh {Γ'} {a}) ⟩
    evalSub (embWk w) ∘ evalWk (fresh {Γ'} {a})  ≈⟨ ∘-pres-≈̇ (evalSub-pres-wk w) (evalWk-pres-π₁ Γ' a) ⟩
    evalWk (drop[ a ] w)                         ∎
  evalSub-pres-wk {Γ} (keep {Δ = Γ'} {a} w) = let open EqReasoning (Sub'-setoid (Γ' `, a) Γ) in begin
    evalSub (embWk (keep[ a ] w))                ≈⟨ evalSub-pres-×-map-id (embWk w) a ⟩
    evalSub (embWk w) ×'-map id'[ evalTy a ]     ≈⟨ ×'-map-pres-≈̇-left (evalSub-pres-wk w) id' ⟩
    evalWk (keep[ a ] w)                         ∎
  evalSub-pres-wk {Γ} (keep# {Δ = Γ'} w) = let open EqReasoning (Sub'-setoid (Γ' #) Γ) in begin
    evalSub (embWk (keep# w))                    ≈⟨ evalSub-pres-lock-map (embWk w) ⟩
    ✦'-map (evalSub (embWk w))                   ≈⟨ ✦'-map-pres-≈̇ (evalSub-pres-wk w) ⟩
    evalWk (keep# w)                             ∎

abstract
  evalSub-pres-id : ∀ (Γ : Ctx) → evalSub idₛ[ Γ ] ≈̇ id'
  evalSub-pres-id Γ = let open EqReasoning (Sub'-setoid Γ Γ) in begin
    evalSub idₛ[ Γ ]  ≈⟨ evalSub-pres-wk idWk[ Γ ] ⟩
    evalWk idWk[ Γ ]  ≈⟨ evalWk-pres-id Γ ⟩
    id'                ∎

module _ {a : Ty} {Δ : Ctx} where
  abstract
    evalTm-pres-∘'' : ∀ (v : Var Γ a) (σ : Sub Δ Γ) → evalTm (substVar σ v) ≈̇ evalVar v [ evalSub σ ]'
    evalTm-pres-∘'' zero             (σ `, t) = ≈̇-sym (×'-beta-right (evalSub σ))
    evalTm-pres-∘'' (succ {b = b} v) (σ `, t) = let open EqReasoning (Tm'-setoid Δ a) in begin
      evalTm (substVar (σ `, t) (succ {b = b} v))     ≈⟨ evalTm-pres-∘'' v σ ⟩
      evalVar v [ evalSub σ ]'                        ≈˘⟨ ∘-pres-≈̇-right (evalVar v) (×'-beta-left (evalTm t)) ⟩
      evalVar v ∘ π₁'[ evalTy b ] ∘ evalSub (σ `, t)  ≈˘⟨ ∘-assoc (evalVar v) π₁'[ evalTy b ] (evalSub (σ `, t)) ⟩
      evalVar (succ {b = b} v) [ evalSub (σ `, t) ]'  ∎

abstract
  evalTm-pres-∘ : ∀ (t : Tm Γ a) → (σ : Sub Δ Γ) → evalTm (substTm σ t) ≈̇ evalTm t [ evalSub σ ]'
  evalTm-pres-∘ (var v) σ = evalTm-pres-∘'' v σ
  evalTm-pres-∘ {a = a} {Δ} (lam {a = a'} t) σ = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (substTm σ (lam t))
      ≈⟨ lam'-pres-≈̇ (evalTm-pres-∘ t (wkSub (fresh {Δ} {a'}) σ `, var zero)) ⟩
    lam' (evalTm t [ evalSub (wkSub (fresh {Δ} {a'}) σ `, var zero) ]')
      ≈⟨ lam'-pres-≈̇ (∘-pres-≈̇-right (evalTm t) (⟨,⟩'-pres-≈̇-left (evalSub-pres-∘' σ (fresh {Δ} {a'})) π₂'[ evalCtx Δ ])) ⟩
    lam' (evalTm t [ ⟨ evalSub σ ∘ evalWk (fresh {Δ} {a'}) , π₂'[ evalCtx Δ ] ⟩' ]' )
      ≈⟨ lam'-pres-≈̇ (∘-pres-≈̇-right (evalTm t) (⟨,⟩'-pres-≈̇-left (∘-pres-≈̇-right (evalSub σ) (evalWk-pres-π₁ Δ a')) π₂'[ evalCtx Δ ])) ⟩
    lam' (evalTm t [ ⟨ evalSub σ ∘ π₁'[ evalTy a' ] , π₂'[ evalCtx Δ ] ⟩' ]')
      ≈˘⟨ lam'-pres-≈̇ (∘-pres-≈̇-right (evalTm t) (⟨,⟩'-pres-≈̇-right (evalSub σ ∘ π₁'[ evalTy a' ]) (id'-unit-left (evalTy a') π₂'[ evalCtx Δ ]))) ⟩
    lam' (evalTm t ∘ evalSub σ ×'-map id'[ evalTy a' ])
      ≈˘⟨ lam'-nat (evalTm t) (evalSub σ) ⟩
    evalTm (lam t) [ evalSub σ ]'
      ∎
  evalTm-pres-∘ {a = a} {Δ} (app t u) σ = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (substTm σ (app t u))
      ≈⟨ app'-pres-≈̇ (evalTm-pres-∘ t σ) (evalTm-pres-∘ u σ) ⟩
    app' (evalTm t [ evalSub σ ]') (evalTm u [ evalSub σ ]')
      ≈˘⟨ app'-nat (evalTm t) (evalTm u) (evalSub σ) ⟩
    evalTm (app t u) [ evalSub σ ]'
      ∎
  evalTm-pres-∘ {a = a} {Δ} (box t) σ = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (substTm σ (box t))
      ≈⟨ box'-pres-≈̇ (evalTm-pres-∘ t (lock σ new)) ⟩
    box' (evalTm t [ evalSub (keep#ₛ σ) ]')
      ≈⟨ box'-pres-≈̇ (∘-pres-≈̇-right (evalTm t) (evalSub-pres-lock-map σ)) ⟩
    box' (evalTm t [ ✦'-map (evalSub σ) ]')
      ≈⟨ box'-nat-dom (evalTm t) (evalSub σ) ⟩
    evalTm (box t) [ evalSub σ ]'
      ∎
  evalTm-pres-∘ {a = a} {Δ} (unbox t e) σ = let open EqReasoning (Tm'-setoid Δ a) in begin
    evalTm (substTm σ (unbox t e))
      ≈⟨ unbox'-pres-≈̇-left (evalTm-pres-∘ t (factorSubₛ e σ)) (evalAcc (factorExtₛ e σ)) ⟩
    unbox' (evalTm t [ evalSub (factorSubₛ e σ) ]') (evalAcc (factorExtₛ e σ))
      ≈⟨ unbox'-nat-dom (evalTm t) (evalSub (factorSubₛ e σ)) (evalAcc (factorExtₛ e σ)) ⟩
    unbox' (evalTm t) (✦'-map (evalSub (factorSubₛ e σ)) ∘ evalAcc (factorExtₛ e σ))
      ≈˘⟨ unbox'-pres-≈̇-right (evalTm t) (acc-nat e σ) ⟩
    unbox' (evalTm t) (evalAcc e ∘ evalSub σ)
      ≈˘⟨ ∘-assoc (λ' (evalTm t)) (evalAcc e) (evalSub σ) ⟩
    evalTm (unbox t e) [ evalSub σ ]'
      ∎

abstract
  evalTm-sound : (s : t ⟶ t') → evalTm t ≈̇ evalTm t'
  evalTm-sound (red-fun {Γ} {a} {b} t u) = let open EqReasoning (Tm'-setoid Γ b) in begin
    evalTm (app (lam t) u)
      ≈⟨ ⇒'-beta (evalTm t) (evalTm u) ⟩
    evalTm t [ ⟨ id'[ evalCtx Γ ] , evalTm u ⟩' ]'
      ≈˘⟨ ∘-pres-≈̇-right (evalTm t) (⟨,⟩'-pres-≈̇-left (evalSub-pres-id Γ) (evalTm u)) ⟩
    evalTm t [ ⟨ evalSub idₛ[ Γ ] , evalTm u ⟩' ]'
      ≈˘⟨ evalTm-pres-∘ t (idₛ `, u) ⟩
    evalTm (substTm (idₛ[ Γ ] `, u) t)
      ∎
  evalTm-sound (exp-fun {Γ} {a} {b} t) = let open EqReasoning (Tm'-setoid Γ (a ⇒ b)) in begin
    evalTm t
      ≈⟨ ⇒'-eta (evalTm t) ⟩
    lam' (app' (evalTm t [ π₁'[ evalTy a ] ]') π₂'[ evalCtx Γ ])
      ≈˘⟨ lam'-pres-≈̇ (app'-pres-≈̇-left (∘-pres-≈̇-right (evalTm t) (evalWk-pres-π₁ Γ a)) π₂'[ evalCtx Γ ]) ⟩
    lam' (app' (evalTm t [ evalWk (fresh {Γ} {a}) ]') π₂'[ evalCtx Γ ])
      ≈˘⟨ lam'-pres-≈̇ (app'-pres-≈̇-left (evalTm-pres-∘' fresh t) π₂'[ evalCtx Γ ]) ⟩
    evalTm (lam (app (wkTm fresh t) (var zero)))
      ∎
  evalTm-sound (red-box {ΓL} {a} {Γ} t e) = let open EqReasoning (Tm'-setoid Γ a) in begin
    evalTm (unbox (box t) e)
      ≈⟨ ∘-pres-≈̇-left (□'-beta (evalTm t)) (evalAcc e) ⟩
    evalTm t [ evalAcc e ]'
      ≈˘⟨ ∘-pres-≈̇-right (evalTm t) (id'-unit-left (✦' evalCtx ΓL) (evalAcc e)) ⟩
    evalTm t [ id'[ ✦' evalCtx ΓL ] ∘ evalAcc e ]'
      ≈˘⟨ ∘-pres-≈̇-right (evalTm t) (∘-pres-≈̇-left ✦'-map-pres-id' (evalAcc e)) ⟩
    evalTm t [ ✦'-map id'[ evalCtx ΓL ] ∘ evalAcc e ]'
      ≈˘⟨ ∘-pres-≈̇-right (evalTm t) (∘-pres-≈̇-left (✦'-map-pres-≈̇ (evalSub-pres-id ΓL)) (evalAcc e)) ⟩
    evalTm t [ evalSub (lock idₛ[ ΓL ] e)  ]'
      ≈˘⟨ evalTm-pres-∘ t (lock idₛ e) ⟩
    evalTm (substTm (lock idₛ[ ΓL ] e) t)
      ∎
  evalTm-sound (exp-box {Γ} {a} t) = let open EqReasoning (Tm'-setoid Γ (□ a)) in begin
    evalTm t
      ≈⟨ □'-eta (evalTm t) ⟩
    box' (λ' (evalTm t))
      ≈˘⟨ box'-pres-≈̇ (id'-unit-right (✦' evalCtx Γ) (λ' (evalTm t))) ⟩
    box' (unbox' (evalTm t) id'[ ✦' evalCtx Γ ])
      ≈˘⟨ box'-pres-≈̇ (unbox'-pres-≈̇-right (evalTm t) η'-unit-right[ evalCtx Γ ]) ⟩
    evalTm (box (unbox t new))
      ∎
  evalTm-sound (cong-lam s)                                         = lam'-pres-≈̇        (evalTm-sound s)
  evalTm-sound (cong-app1 {u = u} s)                                = app'-pres-≈̇-left   (evalTm-sound s) (evalTm u)
  evalTm-sound (cong-app2 {t = t} s)                                = app'-pres-≈̇-right  (evalTm t) (evalTm-sound s)
  evalTm-sound (cong-box s)                                         = box'-pres-≈̇        (evalTm-sound s)
  evalTm-sound (cong-unbox {e = e} s)                               = unbox'-pres-≈̇-left (evalTm-sound s) (evalAcc e)
  evalTm-sound (shift-unbox {ΓLL} {a} t {_ΓLR} {_ΓL} w {_ΓR} {Γ} e) = let open EqReasoning (Tm'-setoid Γ a) in begin
    evalTm (unbox t (extRAssoc (upLFExt w) e))
      ≡⟨⟩
    unbox' (evalTm t) (evalAcc (extRAssoc (upLFExt w) e))
      ≈⟨ unbox'-pres-≈̇-right (evalTm t) (evalAcc-pres-∘ (upLFExt w) e) ⟩
    unbox' (evalTm t) (μ'[ evalCtx ΓLL ] ∘ ✦'-map (evalAcc (upLFExt w)) ∘ evalAcc e)
      ≈⟨ unbox'-pres-≈̇-right (evalTm t) (∘-pres-≈̇-right μ' (∘-pres-≈̇-left (✦'-map-pres-≈̇ (evalAcc-pres-wk w)) (evalAcc e))) ⟩
    unbox' (evalTm t) (μ'[ evalCtx ΓLL ] ∘ ✦'-map (η'[ evalCtx ΓLL ] ∘ evalWk (LFExtToWk w)) ∘ evalAcc e)
      ≈⟨ unbox'-pres-≈̇-right (evalTm t) (∘-pres-≈̇-right μ' (∘-pres-≈̇-left (✦'-map-pres-∘ η' (evalWk (LFExtToWk w))) (evalAcc e))) ⟩
    unbox' (evalTm t) (μ'[ evalCtx ΓLL ] ∘ (✦'-map η'[ evalCtx ΓLL ] ∘ ✦'-map (evalWk (LFExtToWk w))) ∘ evalAcc e)
      ≈⟨ unbox'-pres-≈̇-right (evalTm t) (∘-pres-≈̇-right μ' (∘-assoc (✦'-map η') (✦'-map (evalWk (LFExtToWk w))) (evalAcc e))) ⟩
    unbox' (evalTm t) (μ'[ evalCtx ΓLL ] ∘ ✦'-map η'[ evalCtx ΓLL ] ∘ ✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)
      ≈˘⟨ unbox'-pres-≈̇-right (evalTm t) (∘-assoc μ' (✦'-map η') (✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)) ⟩
    unbox' (evalTm t) ((μ'[ evalCtx ΓLL ] ∘ ✦'-map η'[ evalCtx ΓLL ]) ∘ ✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)
      ≈⟨ unbox'-pres-≈̇-right (evalTm t) (∘-pres-≈̇-left η'-unit-right[ evalCtx ΓLL ] (✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)) ⟩
    unbox' (evalTm t) (id'[ ✦' evalCtx ΓLL ] ∘ ✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)
      ≈⟨ unbox'-pres-≈̇-right (evalTm t) (id'-unit-left (✦' evalCtx ΓLL) (✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)) ⟩
    unbox' (evalTm t) (✦'-map (evalWk (LFExtToWk w)) ∘ evalAcc e)
      ≈˘⟨ unbox'-nat-dom (evalTm t) (evalWk (LFExtToWk w)) (evalAcc e) ⟩
    unbox' (evalTm t [ evalWk (LFExtToWk w) ]') (evalAcc e)
      ≈˘⟨ unbox'-pres-≈̇-left (evalTm-pres-∘' (LFExtToWk w) t) (evalAcc e) ⟩
    unbox' (evalTm (wkTm (LFExtToWk w) t)) (evalAcc e)
      ≡⟨⟩
    evalTm (unbox (wkTm (LFExtToWk w) t) e)
      ∎

module _ {Γ : Ctx} {a : Ty} where
  abstract
    evalTm-sound' : ∀ {t t' : Tm Γ a} (t≈t' : t ≈ t') → evalTm t ≈̇ evalTm t'
    evalTm-sound' ε                     = ≈̇-refl
    evalTm-sound' (inj₁ t⟶t'' ◅ t''≈t') = ≈̇-trans (evalTm-sound t⟶t'') (evalTm-sound' t''≈t')
    evalTm-sound' (inj₂ t⟵t'' ◅ t''≈t') = ≈̇-trans (≈̇-sym (evalTm-sound t⟵t'')) (evalTm-sound' t''≈t')

Generated from commit 2fd14c996b195ef101dff8919e837907ca0a08aa.