Brendan Hart 2019-2020

\begin{code}

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

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

module PCF.Lambda.Substitution
        (pt : propositional-truncations-exist)
        (fe : โˆ€ {๐“ค ๐“ฅ} โ†’ funext ๐“ค ๐“ฅ)
        (pe : propext ๐“คโ‚€)
       where

open PropositionalTruncation pt

open import PCF.Lambda.AbstractSyntax pt
open import UF.Base

ids : {n : โ„•} {ฮ“ : Context n} {A : type} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ“ A
ids x = v x

exts-cong : {n m : โ„•} {ฮ“ : Context n} {ฮ” : Context m} {B : type}
          โ†’ {f g : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A}
          โ†’ (โˆ€ {A} โ†’ f {A = A} โˆผ g)
          โ†’ (โˆ€ {A} โ†’ (exts f {B}) {A = A} โˆผ (exts g))
exts-cong eq Z     = refl
exts-cong eq (S x) = ap (rename S) (eq x)

subst-cong : {n m : โ„•} {ฮ“ : Context n} {ฮ” : Context m} {B : type}
           โ†’ (M M' : PCF ฮ“ B)
           โ†’ (f g : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
           โ†’ M ๏ผ M'
           โ†’ (โˆ€ {A} โ†’ f {A = A} โˆผ g)
           โ†’ subst f M ๏ผ subst g M'

subst-cong Zero .Zero f g refl eq = refl

subst-cong (Succ M) .(Succ M) f g refl eq = ap Succ
                                             (subst-cong M M f g refl eq)

subst-cong (Pred M) .(Pred M) f g refl eq = ap Pred
                                             (subst-cong M M f g refl eq)

subst-cong (IfZero M Mโ‚ Mโ‚‚)
          .(IfZero M Mโ‚ Mโ‚‚) f g refl eq   = apโ‚ƒ IfZero
                                             (subst-cong M M f g refl eq)
                                             (subst-cong Mโ‚ Mโ‚ f g refl eq)
                                             (subst-cong Mโ‚‚ Mโ‚‚ f g refl eq)

subst-cong (ฦ› M) .(ฦ› M) f g refl eq = ap ฦ›
                                       (subst-cong M M
                                         (exts f)
                                         (exts g)
                                         refl
                                         (exts-cong eq))

subst-cong (M ยท Mโ‚) .(M ยท Mโ‚) f g refl eq = apโ‚‚ _ยท_
                                             (subst-cong M M f g refl eq)
                                             (subst-cong Mโ‚ Mโ‚ f g refl eq)

subst-cong (v x) .(v x) f g refl eq = eq x

subst-cong (Fix M) .(Fix M) f g refl eq = ap Fix
                                           (subst-cong M M f g refl eq)

ext-cong : {n m : โ„•} {ฮ“ : Context n} {ฮ” : Context m} {B : type}
         โ†’ {ฯ ฯ' : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A}
         โ†’ (โˆ€ {A} โ†’ ฯ {A = A} โˆผ ฯ')
         โ†’ (โˆ€ {A} โ†’ (ext ฯ {B}) {A = A} โˆผ ext ฯ')
ext-cong eq Z     = refl
ext-cong eq (S x) = ap S (eq x)

compose-ext : {n m k : โ„•}
              {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
              {B : type}
              (ฯ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
              (ฯ' : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ ฮฃ โˆ‹ A)
              {A : type}
            โ†’ (x : (ฮ“ โ€™ B) โˆ‹ A) โ†’ (ext ฯ' โˆ˜ ext ฯ) x ๏ผ ext (ฯ' โˆ˜ ฯ) x
compose-ext ฯ ฯ' Z     = refl
compose-ext ฯ ฯ' (S x) = refl

rename-cong : {n m : โ„•}
              {ฮ“ : Context n} {ฮ” : Context m}
              {B : type}
              (M M' : PCF ฮ“ B)
              (ฯ ฯ' : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
            โ†’ M ๏ผ M'
            โ†’ (โˆ€ {A} โ†’ ฯ {A = A} โˆผ ฯ')
            โ†’ rename ฯ M ๏ผ rename ฯ' M'

rename-cong Zero .Zero ฯ ฯ' refl eq = refl

rename-cong (Succ M) .(Succ M) ฯ ฯ' refl eq =
 ap Succ
  (rename-cong M M ฯ ฯ' refl eq)

rename-cong (Pred M) .(Pred M) ฯ ฯ' refl eq =
 ap Pred
  (rename-cong M M ฯ ฯ' refl eq)

rename-cong (IfZero M Mโ‚ Mโ‚‚) .(IfZero M Mโ‚ Mโ‚‚) ฯ ฯ' refl eq =
 apโ‚ƒ IfZero
  (rename-cong M M ฯ ฯ' refl eq)
  (rename-cong Mโ‚ Mโ‚ ฯ ฯ' refl eq)
  (rename-cong Mโ‚‚ Mโ‚‚ ฯ ฯ' refl eq)

rename-cong (ฦ› M) .(ฦ› M) ฯ ฯ' refl eq =
 ap ฦ›
   (rename-cong M M (ext ฯ) (ext ฯ') refl (ext-cong eq))

rename-cong (M ยท Mโ‚) .(M ยท Mโ‚) ฯ ฯ' refl eq =
 apโ‚‚ _ยท_
  (rename-cong M M ฯ ฯ' refl eq)
  (rename-cong Mโ‚ Mโ‚ ฯ ฯ' refl eq)

rename-cong (v x) .(v x) ฯ ฯ' refl eq =
 ap v
   (eq x)

rename-cong (Fix M) .(Fix M) ฯ ฯ' refl eq =
 ap Fix
   (rename-cong M M ฯ ฯ' refl eq)

compose-rename : {n m k : โ„•}
                 {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
                 {B : type}
                 (M : PCF ฮ“ B)
                 (ฯ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
                 (ฯ' : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ ฮฃ โˆ‹ A)
               โ†’ rename ฯ' (rename ฯ M) ๏ผ rename (ฯ' โˆ˜ ฯ) M

compose-rename Zero ฯ ฯ' = refl

compose-rename (Succ M) ฯ ฯ' = ap Succ (compose-rename M ฯ ฯ')

compose-rename (Pred M) ฯ ฯ' = ap Pred (compose-rename M ฯ ฯ')

compose-rename (IfZero M Mโ‚ Mโ‚‚) ฯ ฯ' = apโ‚ƒ IfZero
                                        (compose-rename M ฯ ฯ')
                                        (compose-rename Mโ‚ ฯ ฯ')
                                        (compose-rename Mโ‚‚ ฯ ฯ')
compose-rename (ฦ› M) ฯ ฯ' = ap ฦ› ฮณ
  where
    ฮณ : rename (ext ฯ') (rename (ext ฯ) M) ๏ผ rename (ext (ฯ' โˆ˜ ฯ)) M
    ฮณ = rename (ext ฯ') (rename (ext ฯ) M) ๏ผโŸจ i โŸฉ
        rename ((ext ฯ') โˆ˜ (ext ฯ)) M      ๏ผโŸจ ii โŸฉ
        rename (ext (ฮป x โ†’ ฯ' (ฯ x))) M    โˆŽ
     where
      i   = compose-rename M (ext ฯ) (ext ฯ')
      ii  = rename-cong M M
             (ฮป {A} x โ†’ ext ฯ' (ext ฯ x))
             (ext (ฮป {A} x โ†’ ฯ' (ฯ x)))
             refl
             (compose-ext ฯ ฯ')

compose-rename (M ยท Mโ‚) ฯ ฯ' = apโ‚‚ _ยท_
                                (compose-rename M ฯ ฯ')
                                (compose-rename Mโ‚ ฯ ฯ')

compose-rename (v x) ฯ ฯ' = refl

compose-rename (Fix M) ฯ ฯ' = ap Fix
                               (compose-rename M ฯ ฯ')

exts-ids : {n : โ„•} {ฮ“ : Context n} {B A : type}
           (x : (ฮ“ โ€™ B) โˆ‹ A)
         โ†’ exts ids x ๏ผ ids x
exts-ids Z     = refl
exts-ids (S x) = refl

sub-id : {n : โ„•}
         {ฮ“ : Context n} {B : type}
         (M : PCF ฮ“ B)
       โ†’ subst ids M ๏ผ M
sub-id Zero = refl
sub-id (Succ M) = ap Succ (sub-id M)
sub-id (Pred M) = ap Pred (sub-id M)
sub-id (IfZero M Mโ‚ Mโ‚‚) = apโ‚ƒ IfZero (sub-id M) (sub-id Mโ‚) (sub-id Mโ‚‚)
sub-id (ฦ› M) = ap ฦ› ฮณ
  where
    ฮณ : subst (exts ids) M ๏ผ M
    ฮณ = subst (exts ids) M ๏ผโŸจ subst-cong M M (exts ids) ids refl exts-ids โŸฉ
        subst ids M        ๏ผโŸจ sub-id M โŸฉ
        M                  โˆŽ

sub-id (M ยท Mโ‚) = apโ‚‚ _ยท_ (sub-id M) (sub-id Mโ‚)
sub-id (v x) = refl
sub-id (Fix M) = ap Fix (sub-id M)

exts-ext-ids :  {n m : โ„•}
                {ฮ“ : Context n} {ฮ” : Context m}
                {B : type}
                (ฯ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
                {A : type}
                (x : (ฮ“ โ€™ B) โˆ‹ A)
             โ†’ (ids โˆ˜ ext ฯ) x ๏ผ exts (ids โˆ˜ ฯ) x
exts-ext-ids ฯ Z     = refl
exts-ext-ids ฯ (S x) = refl

rename-is-a-substitution : {n m : โ„•}
                           {ฮ“ : Context n}
                           {ฮ” : Context m}
                           {A : type}
                           (ฯ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
                           (M : PCF ฮ“ A)
                         โ†’ rename ฯ M ๏ผ subst (ids โˆ˜ ฯ) M
rename-is-a-substitution ฯ Zero = refl
rename-is-a-substitution ฯ (Succ M) = ap Succ (rename-is-a-substitution ฯ M)
rename-is-a-substitution ฯ (Pred M) = ap Pred (rename-is-a-substitution ฯ M)
rename-is-a-substitution ฯ (IfZero M Mโ‚ Mโ‚‚) = apโ‚ƒ IfZero
                                               (rename-is-a-substitution ฯ M)
                                               (rename-is-a-substitution ฯ Mโ‚)
                                               (rename-is-a-substitution ฯ Mโ‚‚)
rename-is-a-substitution ฯ (ฦ› M) = ap ฦ› ฮณ
  where
    ฮณ : rename (ext ฯ) M ๏ผ subst (exts (ids โˆ˜ ฯ)) M
    ฮณ = rename (ext ฯ) M         ๏ผโŸจ i โŸฉ
        subst (ids โˆ˜ ext ฯ) M    ๏ผโŸจ ii โŸฉ
        subst (exts (ids โˆ˜ ฯ)) M โˆŽ
      where
        i = rename-is-a-substitution (ext ฯ) M
        ii = subst-cong M M (ids โˆ˜ ext ฯ) (exts (ids โˆ˜ ฯ)) refl (exts-ext-ids ฯ)

rename-is-a-substitution ฯ (M ยท Mโ‚) = apโ‚‚ _ยท_
                                      (rename-is-a-substitution ฯ M)
                                      (rename-is-a-substitution ฯ Mโ‚)

rename-is-a-substitution ฯ (v x) = refl
rename-is-a-substitution ฯ (Fix M) = ap Fix (rename-is-a-substitution ฯ M)

_๏ผ›_ : {n m k : โ„•}
       {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
      โ†’ (โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
      โ†’ (โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮฃ A)
      โ†’ (โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮฃ A)
_๏ผ›_ f g x = subst g (f x)

sub-ids-right : {n m : โ„•}
                {ฮ“ : Context n} {ฮ” : Context m}
                (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
                {A : type}
                (x : ฮ“ โˆ‹ A)
              โ†’ (f ๏ผ› ids) x ๏ผ f x
sub-ids-right f x = sub-id (f x)

ext-comp : {a b c : โ„•}
           {ฮ“ : Context a} {ฮ” : Context b} {ฮจ : Context c}
           (ฯโ‚ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
           (ฯโ‚‚ : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ ฮจ โˆ‹ A)
           {B A : type}
           (x : (ฮ“ โ€™ B) โˆ‹ A)
         โ†’ (ext ฯโ‚‚ โˆ˜ ext ฯโ‚) x ๏ผ ext (ฯโ‚‚ โˆ˜ ฯโ‚) x
ext-comp ฯโ‚ ฯโ‚‚ Z     = refl
ext-comp ฯโ‚ ฯโ‚‚ (S x) = refl

exts-ext : {a b c : โ„•}
           {ฮ“ : Context a} {ฮ” : Context b} {ฮจ : Context c}
           (B : type)
           (ฯ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
           (ฯƒ : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮจ A)
           {A : type}
           (x : (ฮ“ โ€™ B) โˆ‹ A)
          โ†’ (exts ฯƒ โˆ˜ ext ฯ) x ๏ผ exts (ฯƒ โˆ˜ ฯ) x
exts-ext B ฯ ฯƒ  Z    = refl
exts-ext B ฯ ฯƒ (S x) = refl

rename-comp : {a b c : โ„•}
              {ฮ“ : Context a} {ฮ” : Context b} {ฮจ : Context c}
              {B : type}
              (ฯโ‚ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
              (ฯโ‚‚ : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ ฮจ โˆ‹ A)
              (t : PCF ฮ“ B)
            โ†’ rename ฯโ‚‚ (rename ฯโ‚ t) ๏ผ rename (ฯโ‚‚ โˆ˜ ฯโ‚) t
rename-comp ฯโ‚ ฯโ‚‚ Zero = refl
rename-comp ฯโ‚ ฯโ‚‚ (Succ t) = ap Succ (rename-comp ฯโ‚ ฯโ‚‚ t)
rename-comp ฯโ‚ ฯโ‚‚ (Pred t) = ap Pred (rename-comp ฯโ‚ ฯโ‚‚ t)
rename-comp ฯโ‚ ฯโ‚‚ (IfZero t tโ‚ tโ‚‚) = apโ‚ƒ IfZero
                                      (rename-comp ฯโ‚ ฯโ‚‚ t)
                                      (rename-comp ฯโ‚ ฯโ‚‚ tโ‚)
                                      (rename-comp ฯโ‚ ฯโ‚‚ tโ‚‚)

rename-comp ฯโ‚ ฯโ‚‚ (ฦ› {_} {_} {ฯƒ} t) = ap ฦ› ฮณ
  where
    IH : rename (ext ฯโ‚‚) (rename (ext ฯโ‚) t) ๏ผ rename (ext ฯโ‚‚ โˆ˜ ext ฯโ‚) t
    IH = rename-comp (ext ฯโ‚) (ext ฯโ‚‚) t

    i : rename (ext ฯโ‚‚ โˆ˜ ext ฯโ‚) t
      ๏ผ rename (ฮป {A} โ†’ ext (ฮป {A = Aโ‚} x โ†’ ฯโ‚‚ (ฯโ‚ x))) t
    i = rename-cong t t (ext ฯโ‚‚ โˆ˜ ext ฯโ‚) (ext (ฯโ‚‚ โˆ˜ ฯโ‚)) refl (ext-comp ฯโ‚ ฯโ‚‚)

    ฮณ : rename (ext ฯโ‚‚) (rename (ext ฯโ‚) t) ๏ผ rename (ext (ฯโ‚‚ โˆ˜ ฯโ‚)) t
    ฮณ = IH โˆ™ i

rename-comp ฯโ‚ ฯโ‚‚ (t ยท tโ‚) = apโ‚‚ _ยท_
                             (rename-comp ฯโ‚ ฯโ‚‚ t)
                             (rename-comp ฯโ‚ ฯโ‚‚ tโ‚)

rename-comp ฯโ‚ ฯโ‚‚ (v x) = refl
rename-comp ฯโ‚ ฯโ‚‚ (Fix t) = ap Fix (rename-comp ฯโ‚ ฯโ‚‚ t)

subst-rename-comp : {a b c : โ„•}
                    {ฮ“ : Context a} {ฮ” : Context b} {ฮจ : Context c}
                    {A : type}
                    (ฯ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ ฮ” โˆ‹ A)
                    (ฯƒ : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮจ A)
                    (M : PCF ฮ“ A)
                  โ†’ subst ฯƒ (rename ฯ M) ๏ผ subst (ฯƒ โˆ˜ ฯ) M
subst-rename-comp ฯ ฯƒ Zero = refl
subst-rename-comp ฯ ฯƒ (Succ M) = ap Succ (subst-rename-comp ฯ ฯƒ M)
subst-rename-comp ฯ ฯƒ (Pred M) = ap Pred (subst-rename-comp ฯ ฯƒ M)
subst-rename-comp ฯ ฯƒ (IfZero M Mโ‚ Mโ‚‚) = apโ‚ƒ IfZero
                                          (subst-rename-comp ฯ ฯƒ M)
                                          (subst-rename-comp ฯ ฯƒ Mโ‚)
                                          (subst-rename-comp ฯ ฯƒ Mโ‚‚)

subst-rename-comp ฯ ฯƒ (ฦ› {_} {_} {A} M) = ap ฦ› ฮณ
  where
    IH : subst (exts ฯƒ) (rename (ext ฯ) M) ๏ผ subst (exts ฯƒ โˆ˜ ext ฯ) M
    IH = subst-rename-comp (ext ฯ) (exts ฯƒ) M

    ฮด : subst (exts ฯƒ โˆ˜ ext ฯ) M ๏ผ subst (exts (ฯƒ โˆ˜ ฯ)) M
    ฮด = subst-cong M M
         (ฮป {A} โ†’ exts ฯƒ โˆ˜ ext ฯ) (exts (ฮป {A} โ†’ ฯƒ โˆ˜ ฯ))
         refl
         (exts-ext A ฯ ฯƒ)

    ฮณ : subst (exts ฯƒ) (rename (ext ฯ) M) ๏ผ subst (exts (ฯƒ โˆ˜ ฯ)) M
    ฮณ = IH โˆ™ ฮด

subst-rename-comp ฯ ฯƒ (M ยท Mโ‚) = apโ‚‚ _ยท_
                                  (subst-rename-comp ฯ ฯƒ M)
                                  (subst-rename-comp ฯ ฯƒ Mโ‚)

subst-rename-comp ฯ ฯƒ (v x) = refl
subst-rename-comp ฯ ฯƒ (Fix M) = ap Fix (subst-rename-comp ฯ ฯƒ M)

rename-exts : {a b c : โ„•}
              {ฮ“ : Context a} {ฮ” : Context b} {ฮจ : Context c}
              {B : type}
              (ฯƒ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
              (ฯ : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ ฮจ โˆ‹ A)
              {A : type}
              (x : (ฮ“ โ€™ B) โˆ‹ A)
            โ†’ rename (ext ฯ) (exts ฯƒ x) ๏ผ exts (rename ฯ โˆ˜ ฯƒ) x
rename-exts ฯƒ ฯ Z     = refl
rename-exts ฯƒ ฯ (S x) = ฮณ
  where
    ฮณ : rename (ext ฯ) (exts ฯƒ (S x)) ๏ผ rename S (rename ฯ (ฯƒ x))
    ฮณ = rename (ext ฯ) (exts ฯƒ (S x)) ๏ผโŸจ i โŸฉ
        rename (S โˆ˜ ฯ) (ฯƒ x)          ๏ผโŸจ ii โŸฉ
        rename S (rename ฯ (ฯƒ x))     โˆŽ
      where
        i  = rename-comp S (ext ฯ) (ฯƒ x)
        ii = rename-comp ฯ S (ฯƒ x) โปยน

subst-rename-commute : {a b c : โ„•}
                       {ฮ“ : Context a} {ฮ” : Context b} {ฮจ : Context c}
                       {A : type}
                       (ฯƒ : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
                       (ฯ : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ ฮจ โˆ‹ A)
                       (M : PCF ฮ“ A)
                     โ†’ rename ฯ (subst ฯƒ M) ๏ผ subst (rename ฯ โˆ˜ ฯƒ) M
subst-rename-commute ฯƒ ฯ Zero = refl
subst-rename-commute ฯƒ ฯ (Succ M) = ap Succ
                                     (subst-rename-commute ฯƒ ฯ M)

subst-rename-commute ฯƒ ฯ (Pred M) = ap Pred
                                     (subst-rename-commute ฯƒ ฯ M)

subst-rename-commute ฯƒ ฯ (IfZero M Mโ‚ Mโ‚‚) = apโ‚ƒ IfZero
                                             (subst-rename-commute ฯƒ ฯ M)
                                             (subst-rename-commute ฯƒ ฯ Mโ‚)
                                             (subst-rename-commute ฯƒ ฯ Mโ‚‚)
subst-rename-commute ฯƒ ฯ (ฦ› M) = ap ฦ› ฮณ
  where
    IH : rename (ext ฯ) (subst (exts ฯƒ) M) ๏ผ subst (rename (ext ฯ) โˆ˜ exts ฯƒ) M
    IH = subst-rename-commute (exts ฯƒ) (ext ฯ) M

    ฮด : subst (rename (ext ฯ) โˆ˜ exts ฯƒ) M
      ๏ผ subst (exts (rename ฯ โˆ˜ ฯƒ)) M
    ฮด = subst-cong M M
         (rename (ext ฯ) โˆ˜ exts ฯƒ)
         (exts (rename ฯ โˆ˜ ฯƒ))
         refl
         (rename-exts ฯƒ ฯ)

    ฮณ : rename (ext ฯ) (subst (exts ฯƒ) M) ๏ผ subst (exts (rename ฯ โˆ˜ ฯƒ)) M
    ฮณ = IH โˆ™ ฮด

subst-rename-commute ฯƒ ฯ (M ยท Mโ‚) = apโ‚‚ _ยท_
                                     (subst-rename-commute ฯƒ ฯ M)
                                     (subst-rename-commute ฯƒ ฯ Mโ‚)

subst-rename-commute ฯƒ ฯ (v x) = refl
subst-rename-commute ฯƒ ฯ (Fix M) = ap Fix (subst-rename-commute ฯƒ ฯ M)

exts-seq : {n m k : โ„•}
           {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
           {B : type}
           (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
           (g : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮฃ A)
           {A : type}
           (x : (ฮ“ โ€™ B) โˆ‹ A)
         โ†’ (exts f ๏ผ› exts g) x ๏ผ exts (f ๏ผ› g) x
exts-seq f g  Z    = refl
exts-seq f g (S x) = subst (exts g) (rename S (f x)) ๏ผโŸจ i โŸฉ
                      subst (exts g โˆ˜ S) (f x)       ๏ผโŸจ refl โŸฉ
                      subst (rename S โˆ˜ g) (f x)     ๏ผโŸจ ii โŸฉ
                      rename S (subst g (f x))       โˆŽ
  where
    i  = subst-rename-comp S (exts g) (f x)
    ii = subst-rename-commute g S (f x) โปยน

sub-sub-lem : {n m k : โ„•}
              {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
              {B : type}
              (M : PCF ฮ“ B)
              (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
              (g : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮฃ A)
             โ†’ subst g (subst f M) ๏ผ subst (f ๏ผ› g) M
sub-sub-lem Zero f g = refl
sub-sub-lem (Succ M) f g = ap Succ (sub-sub-lem M f g)
sub-sub-lem (Pred M) f g = ap Pred (sub-sub-lem M f g)
sub-sub-lem (IfZero M Mโ‚ Mโ‚‚) f g = apโ‚ƒ IfZero
                                    (sub-sub-lem M f g)
                                    (sub-sub-lem Mโ‚ f g)
                                    (sub-sub-lem Mโ‚‚ f g)
sub-sub-lem (ฦ› M) f g = ap ฦ› ฮณ
  where
    IH : subst (exts g) (subst (exts f) M) ๏ผ subst (exts f ๏ผ› exts g) M
    IH = sub-sub-lem M (exts f) (exts g)

    ฮด : subst (exts f ๏ผ› exts g) M ๏ผ subst (exts (f ๏ผ› g)) M
    ฮด = subst-cong M M (exts f ๏ผ› exts g) (exts (f ๏ผ› g)) refl (exts-seq f g)

    ฮณ : subst (exts g) (subst (exts f) M) ๏ผ subst (exts (f ๏ผ› g)) M
    ฮณ = IH โˆ™ ฮด

sub-sub-lem (M ยท Mโ‚) f g = apโ‚‚ _ยท_ (sub-sub-lem M f g) (sub-sub-lem Mโ‚ f g)
sub-sub-lem (v x) f g = refl
sub-sub-lem (Fix M) f g = ap Fix (sub-sub-lem M f g)

cons-cong : {n m : โ„•}
            {ฮ“ : Context n} {ฮ” : Context m}
            {B : type}
            {M M' : PCF ฮ” B}
            {f g : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A}
          โ†’ M ๏ผ M'
          โ†’ (โˆ€ {A} โ†’ f {A = A} โˆผ g )
          โ†’ (โˆ€ {A} โ†’ (x : (ฮ“ โ€™ B) โˆ‹ A) โ†’ extend-with M f x ๏ผ extend-with M' g x)
cons-cong refl eq Z     = refl
cons-cong refl eq (S x) = eq x

exts-extend-S : {n m : โ„•}
                {ฮ“ : Context n} {ฮ” : Context m}
                {B : type}
                (f : โˆ€ {A} โ†’ (x : ฮ“ โˆ‹ A) โ†’ PCF ฮ” A)
                {A : type}
                (x : (ฮ“ โ€™ B) โˆ‹ A)
              โ†’ exts f x ๏ผ extend-with (v Z) (f ๏ผ› (ids โˆ˜ S)) x
exts-extend-S f Z     = refl
exts-extend-S f (S x) = rename-is-a-substitution S (f x)

๏ผ›-cong : {n m k : โ„•}
          {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
          (f g : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
          (h j : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮฃ A)
         โ†’ (โˆ€ {A} โ†’ f {A = A} โˆผ g)
         โ†’ (โˆ€ {A} โ†’ h {A = A} โˆผ j)
         โ†’ {A : type}
           (x : ฮ“ โˆ‹ A)
         โ†’ (f ๏ผ› h) x ๏ผ (g ๏ผ› j) x
๏ผ›-cong f g h j x xโ‚ xโ‚‚ = subst-cong (f xโ‚‚) (g xโ‚‚) h j (x xโ‚‚) xโ‚

๏ผ›-assoc : {n m k l : โ„•}
          {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k} {ฯˆ : Context l}
          (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
          (g : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮฃ A)
          (h : โˆ€ {A} โ†’ ฮฃ โˆ‹ A โ†’ PCF ฯˆ A)
          {A : type}
          (x : ฮ“ โˆ‹ A)
        โ†’ ((f ๏ผ› g) ๏ผ› h) x ๏ผ (f ๏ผ› (g ๏ผ› h)) x

๏ผ›-assoc f g h x = sub-sub-lem (f x) g h

subst-Z-cons-ids : {n : โ„•}
                   {ฮ“ : Context n}
                   {B : type}
                   (Mโ‚ : PCF ฮ“ B)
                   {A : type}
                   (x : (ฮ“ โ€™ B) โˆ‹ A)
                 โ†’ replace-first B ฮ“ Mโ‚ x ๏ผ extend-with Mโ‚ ids x
subst-Z-cons-ids Mโ‚ Z     = refl
subst-Z-cons-ids Mโ‚ (S x) = refl

sub-dist : {n m k : โ„•}
           {ฮ“ : Context n} {ฮ” : Context m} {ฮฃ : Context k}
           {B : type}
           (M : PCF ฮ” B)
           (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
           (g : โˆ€ {A} โ†’ ฮ” โˆ‹ A โ†’ PCF ฮฃ A)
           {A : type}
           (x : (ฮ“ โ€™ B) โˆ‹ A)
         โ†’ (extend-with M f ๏ผ› g) x ๏ผ (extend-with (subst g M) (f ๏ผ› g)) x
sub-dist M f g Z     = refl
sub-dist M f g (S x) = refl

extend-replace-first : {C : type}
                       {n m : โ„•}
                       {ฮ“ : Context n} {ฮ” : Context m}
                       (Mโ‚ : PCF ฮ” C)
                       (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
                       {B : type}
                       (x : (ฮ“ โ€™ C) โˆ‹ B)
                     โ†’ extend-with Mโ‚ f x ๏ผ (exts f ๏ผ› replace-first C ฮ” Mโ‚) x
extend-replace-first {ฯƒ} {n} {m} {ฮ“} {ฮ”} Mโ‚ f x = ฮณ โปยน
 where
  ฮณ : (exts f ๏ผ› replace-first ฯƒ ฮ” Mโ‚) x ๏ผ extend-with Mโ‚ f x
  ฮณ = (exts f ๏ผ› replace-first ฯƒ ฮ” Mโ‚) x                               ๏ผโŸจ i โŸฉ
        ((extend-with (v Z) (f ๏ผ› (ids โˆ˜ S))) ๏ผ› extend-with Mโ‚ ids) x ๏ผโŸจ ii โŸฉ
         extend-with (subst (extend-with Mโ‚ ids) (v Z)) ((f ๏ผ› (ids โˆ˜ S)) ๏ผ›
         extend-with Mโ‚ ids) x                                         ๏ผโŸจ iii โŸฉ
         extend-with Mโ‚ (((f ๏ผ› (ids โˆ˜ S)) ๏ผ› extend-with Mโ‚ ids)) x   ๏ผโŸจ iv โŸฉ
         extend-with Mโ‚ (f ๏ผ› ((ids โˆ˜ S) ๏ผ› extend-with Mโ‚ ids)) x     ๏ผโŸจ iiiii โŸฉ
         extend-with Mโ‚ (f ๏ผ› ids) x                                   ๏ผโŸจ vi โŸฉ
         extend-with Mโ‚ f x                                            โˆŽ
   where
    i     = ๏ผ›-cong
             (exts f)
             (extend-with (v Z) (f ๏ผ› (ids โˆ˜ S)))
             (replace-first ฯƒ ฮ” Mโ‚)
             (extend-with Mโ‚ ids)
             (exts-extend-S f)
             (subst-Z-cons-ids Mโ‚)
             x

    ii    = sub-dist (v Z) (f ๏ผ› (ids โˆ˜ S)) (extend-with Mโ‚ ids) x
    iii   = cons-cong refl (ฮป xโ‚ โ†’ refl) x
    iv    = cons-cong refl (๏ผ›-assoc f (ids โˆ˜ S) (extend-with Mโ‚ v)) x
    iiiii = cons-cong refl (ฮป xโ‚ โ†’ refl) x
    vi    = cons-cong refl (sub-ids-right f) x

subst-ext : {A B : type}
            {n m : โ„•}
            {ฮ“ : Context n} {ฮ” : Context m}
            (M : PCF (ฮ“ โ€™ A) B) (Mโ‚ : PCF ฮ” A)
            (f : โˆ€ {A} โ†’ ฮ“ โˆ‹ A โ†’ PCF ฮ” A)
          โ†’ subst (extend-with Mโ‚ f) M
          ๏ผ subst (replace-first A ฮ” Mโ‚) (subst (exts f) M)
subst-ext {ฯƒ} {ฯ„} {n} {m} {ฮ“} {ฮ”} M Mโ‚ f = ii โˆ™ i โปยน
  where
    i : subst (replace-first ฯƒ ฮ” Mโ‚) (subst (exts f) M)
      ๏ผ subst (exts f ๏ผ› (replace-first ฯƒ ฮ” Mโ‚)) M
    i = sub-sub-lem M (exts f) (replace-first ฯƒ ฮ” Mโ‚)

    ii : subst (extend-with Mโ‚ f) M
       ๏ผ subst (exts f ๏ผ› replace-first ฯƒ ฮ” Mโ‚) M
    ii = subst-cong M M
          (extend-with Mโ‚ f)
          (exts f ๏ผ› replace-first ฯƒ ฮ” Mโ‚)
          refl
          (extend-replace-first Mโ‚ f)

\end{code}