Brendan Hart 2019-2020

\begin{code}

{-# OPTIONS --safe --without-K --lossy-unification #-}

open import MLTT.Spartan
open import UF.FunExt
open import UF.PropTrunc
open import UF.Subsingletons

module PCF.Lambda.SubstitutionDenotational
        (pt : propositional-truncations-exist)
        (fe : ∀ {𝓤 𝓥} → funext 𝓤 𝓥)
        (pe : propext 𝓤₀)
       where

open PropositionalTruncation pt

open import DomainTheory.Basics.Dcpo pt fe 𝓤₀
open import DomainTheory.Basics.LeastFixedPoint pt fe 𝓤₀
open import DomainTheory.Basics.Pointed pt fe 𝓤₀
open import DomainTheory.Basics.Products pt fe
open import Lifting.Monad 𝓤₀ hiding (μ)
open import Naturals.Properties
open import PCF.Combinatory.PCFCombinators pt fe 𝓤₀
open import PCF.Lambda.AbstractSyntax pt
open import PCF.Lambda.ScottModelOfContexts pt fe pe
open import PCF.Lambda.ScottModelOfTerms pt fe pe
open import PCF.Lambda.ScottModelOfTypes pt fe pe
open import UF.Base

open DcpoProductsGeneral 𝓤₀
open IfZeroDenotationalSemantics pe

replace-first-lemma : {n : ℕ} {Γ : Context n} {σ τ : type}
                      (x : (Γ ’ τ) ∋ σ)
                      (d : ⟨ (【 Γ 】 ⁻) ⟩)
                      (T : PCF Γ τ)
                    → (pr₁ ⟦ v x ⟧ₑ (d , pr₁ ⟦ T ⟧ₑ d))
                    ＝ pr₁ ⟦ replace-first τ Γ T x ⟧ₑ d
replace-first-lemma {n} {Γ} {σ} {.σ} Z    d T = refl
replace-first-lemma {n} {Γ} {σ} {τ} (S x) d T = refl

extract-S-lemma : {n : ℕ}
                  {Γ : Context n}
                  {σ : type}
                  (d : ⟨ (【 Γ 】 ⁻) ⟩)
                  (e : ⟨ (⟦ σ ⟧ ⁻) ⟩)
                  {A : type}
                  (x : Γ ∋ A)
                → extract x d ＝ extract (S {n} {Γ} {A} {σ} x) (d , e)
extract-S-lemma d e Z     = refl
extract-S-lemma d e (S x) = refl

rename-lemma : {n m : ℕ}
               {Γ : Context n} {Δ : Context m}
               {σ : type}
               (M : PCF Γ σ)
               (ρ : ∀ {A} → Γ ∋ A → Δ ∋ A)
               (d : ⟨ (【 Δ 】 ⁻) ⟩)
               (e : ⟨ (【 Γ 】 ⁻) ⟩)
             → ({A : type} (x : Γ ∋ A) → extract x e ＝ extract (ρ x) d)
             → pr₁ ⟦ rename ρ M ⟧ₑ d ＝ pr₁ ⟦ M ⟧ₑ e
rename-lemma Zero ρ d e eq = refl
rename-lemma (Succ M) ρ d e eq = ap (𝓛̇ succ) (rename-lemma M ρ d e eq)
rename-lemma (Pred M) ρ d e eq = ap (𝓛̇ pred) (rename-lemma M ρ d e eq)
rename-lemma (IfZero M M₁ M₂) ρ d e eq =
 ap₃
 (λ x₁ x₂ x₃ → pr₁ (⦅ifZero⦆₁ x₂ x₃) x₁)
 (rename-lemma M ρ d e eq)
 (rename-lemma M₁ ρ d e eq) (rename-lemma M₂ ρ d e eq)

rename-lemma (ƛ {n} {Γ} {σ} {τ} M) ρ d e eq = γ
 where
  IH : (λ z → pr₁ ⟦ rename (ext ρ) M ⟧ₑ (d , z)) ∼ (λ z → pr₁ ⟦ M ⟧ₑ (e , z))
  IH z = rename-lemma M (ext ρ) (d , z) (e , z) g
   where
     g : ∀ {A} → (x : (Γ ’ σ) ∋ A) → extract x (e , z) ＝ extract (ext ρ x) (d , z)
     g Z = refl
     g (S x) = eq x

  γ : pr₁ ⟦ rename ρ (ƛ M) ⟧ₑ d ＝ pr₁ ⟦ ƛ M ⟧ₑ e
  γ = to-subtype-＝ (being-continuous-is-prop (⟦ σ ⟧ ⁻) (⟦ τ ⟧ ⁻)) (dfunext fe IH)

rename-lemma (M · M₁) ρ d e eq =
 ap₂
  pr₁
  (rename-lemma M ρ d e eq)
  (rename-lemma M₁ ρ d e eq)

rename-lemma (v x) ρ d e eq = eq x ⁻¹
rename-lemma (Fix {_} {_} {σ} M) ρ d e eq =
 ap
  (pr₁ (μ ⟦ σ ⟧))
  (rename-lemma M ρ d e eq)

substitution-lemma : {n : ℕ}{Γ : Context n}
                     {m : ℕ}{Δ : Context m}
                     {σ : type}
                     (M : PCF Γ σ)
                     (f : ∀ {A} → Γ ∋ A → PCF Δ A)
                     (e : ⟨ (【 Γ 】 ⁻) ⟩)
                     (d : ⟨ (【 Δ 】 ⁻) ⟩)
                     (g : ∀ {A} → (x : Γ ∋ A) → pr₁ ⟦ v x ⟧ₑ e ＝ pr₁ ⟦ f x ⟧ₑ d )
                   → pr₁ ⟦ M ⟧ₑ e ＝ pr₁ ⟦ subst f M ⟧ₑ d
substitution-lemma Zero f e d g = refl
substitution-lemma (Succ M) f e d g = ap (𝓛̇ succ) (substitution-lemma M f e d g)
substitution-lemma (Pred M) f e d g = ap (𝓛̇ pred) (substitution-lemma M f e d g)
substitution-lemma (IfZero M M₁ M₂) f e d g =
 pr₁ (⦅ifZero⦆₁ (pr₁ ⟦ M₁ ⟧ₑ e) (pr₁ ⟦ M₂ ⟧ₑ e)) (pr₁ ⟦ M ⟧ₑ e)                        ＝⟨ i ⟩
 pr₁ (⦅ifZero⦆₁ (pr₁ ⟦ M₁ ⟧ₑ e) (pr₁ ⟦ M₂ ⟧ₑ e)) (pr₁ ⟦ subst f M ⟧ₑ d)                ＝⟨ ii ⟩
 pr₁ (⦅ifZero⦆₁ (pr₁ ⟦ subst f M₁ ⟧ₑ d) (pr₁ ⟦ M₂ ⟧ₑ e)) (pr₁ ⟦ subst f M ⟧ₑ d)        ＝⟨ iii ⟩
 pr₁ (⦅ifZero⦆₁ (pr₁ ⟦ subst f M₁ ⟧ₑ d) (pr₁ ⟦ subst f M₂ ⟧ₑ d)) (pr₁ ⟦ subst f M ⟧ₑ d) ∎
 where
  i = ap
      (pr₁ (⦅ifZero⦆₁ (pr₁ ⟦ M₁ ⟧ₑ e) (pr₁ ⟦ M₂ ⟧ₑ e)))
      (substitution-lemma M f e d g)

  ii = ap
        (λ - → pr₁ (⦅ifZero⦆₁ - (pr₁ ⟦ M₂ ⟧ₑ e)) (pr₁ ⟦ subst f M ⟧ₑ d))
        (substitution-lemma M₁ f e d g)

  iii = ap
         (λ - → pr₁ (⦅ifZero⦆₁ (pr₁ ⟦ subst f M₁ ⟧ₑ d) -) (pr₁ ⟦ subst f M ⟧ₑ d))
         (substitution-lemma M₂ f e d g)

substitution-lemma {_} {_} {m} {Δ} (ƛ {n} {Γ} {σ} {τ} M) f e d g = e₂
 where
   e₁ : (pr₁ (pr₁ ⟦ ƛ M ⟧ₑ e)) ∼ (pr₁ (pr₁ ⟦ subst f (ƛ M) ⟧ₑ d))
   e₁ x = substitution-lemma M (exts f) (e , x) (d , x) new_g
    where
     new_g : {A : type}
             (z : (Γ ’ σ) ∋ A)
           → pr₁ ⟦ v z ⟧ₑ (e , x) ＝ pr₁ ⟦ exts f z ⟧ₑ (d , x)
     new_g     Z     = refl
     new_g {A} (S z) =
      pr₁ ⟦ v (S {n} {Γ} {A} {σ} z) ⟧ₑ (e , x) ＝⟨ refl ⟩
      pr₁ ⟦ v z ⟧ₑ e                           ＝⟨  g z ⟩
      pr₁ ⟦ f z ⟧ₑ d                           ＝⟨ i ⟩
      pr₁ ⟦ exts f (S z) ⟧ₑ (d , x)            ∎
       where
        i = (rename-lemma (f z) S (d , x) d (λ x₁ → refl)) ⁻¹

   e₂ : pr₁ ⟦ ƛ M ⟧ₑ e ＝ pr₁ ⟦ subst f (ƛ M) ⟧ₑ d
   e₂ = to-subtype-＝
         (being-continuous-is-prop (⟦ σ ⟧ ⁻) (⟦ τ ⟧ ⁻))
         (dfunext fe e₁)

substitution-lemma (M · M₁) f e d g = γ
 where
  IH₁ : pr₁ ⟦ M₁ ⟧ₑ e ＝ pr₁ ⟦ subst f M₁ ⟧ₑ d
  IH₁ = substitution-lemma M₁ f e d g
  IH : pr₁ ⟦ M ⟧ₑ e ＝ pr₁ ⟦ subst f M ⟧ₑ d
  IH = substitution-lemma M f e d g

  γ = pr₁ (pr₁ ⟦ M ⟧ₑ e) (pr₁ ⟦ M₁ ⟧ₑ e)                               ＝⟨ i ⟩
      pr₁ (pr₁ ⟦ M ⟧ₑ e) (pr₁ ⟦ subst f M₁ ⟧ₑ d)                       ＝⟨ ii ⟩
      pr₁ (pr₁ ⟦ subst (λ {A} → f) M ⟧ₑ d) (pr₁ ⟦ subst (λ {A} → f) M₁ ⟧ₑ d)  ∎
   where
    i  = ap (pr₁ (pr₁ ⟦ M ⟧ₑ e)) IH₁
    ii = ap (λ - → pr₁ - (pr₁ ⟦ subst f M₁ ⟧ₑ d)) IH

substitution-lemma {n} {Γ} {m} {Δ} (v x) f e d g = g x
substitution-lemma {n} {Γ} {m} {Δ} {σ} (Fix M) f e d g =
 ap
  (λ - → pr₁ (μ ⟦ σ ⟧ ) -)
  (substitution-lemma M f e d g)

β-equality : {n : ℕ}
             {Γ : Context n}
             {σ τ : type}
             (E : PCF (Γ ’ τ) σ)
             (T : PCF Γ τ)
             (d : ⟨ (【 Γ 】 ⁻) ⟩)
           → pr₁ ⟦ (ƛ E) · T ⟧ₑ d ＝ pr₁ ⟦ E [ T ] ⟧ₑ d
β-equality {n} {Γ} {σ} {τ} E T d =
 substitution-lemma E (replace-first τ Γ T) (d , (pr₁ ⟦ T ⟧ₑ d)) d g
  where
    g : {A : type}
        (x : (Γ ’ τ) ∋ A)
      → pr₁ ⟦ v x ⟧ₑ (d , pr₁ ⟦ T ⟧ₑ d) ＝ pr₁ ⟦ replace-first τ Γ T x ⟧ₑ d
    g Z     = refl
    g (S x) = refl

\end{code}
