\begin{code}
module PCF.Environments where

open import Data.Bool.Base 
  using (Bool; if_then_else_)
open import Data.Maybe.Base
  using (Maybe; just; nothing)
open import Agda.Builtin.Nat
  using (Nat; _==_)
open import Relation.Binary.PropositionalEquality.Core
  using (_≔_; refl; trans; cong)

open import PCF.Domain-Notation
  using (⊄)
open import PCF.Types
  using (Types; ι; o; _⇒_; š’Ÿ)
open import PCF.Variables
  using (š’±; var; Env)

-- ρ⊄ is the initial environment

ρ⊄ : Env
ρ⊄ α = ⊄

-- (ρ [ x / α ]) α′ = x when α and α′ are identical, otherwise ρ α′

_[_/_] : {σ : Types} → Env → š’Ÿ σ → š’± σ → Env
ρ [ x / α ] = Ī» α′ → h ρ x α α′ (α ==V α′) where

  h : {σ Ļ„ : Types} → Env → š’Ÿ σ → š’± σ → š’± Ļ„ → Maybe (σ ≔ Ļ„) → š’Ÿ Ļ„
  h ρ x α α′ (just refl)  = x
  h ρ x α α′ nothing      = ρ α′

  _==T_ : (σ Ļ„ : Types) → Maybe (σ ≔ Ļ„)
  (σ ⇒ Ļ„) ==T (Ļƒā€² ⇒ τ′) = f (σ ==T Ļƒā€²) (Ļ„ ==T τ′) where
        f : Maybe (σ ≔ Ļƒā€²) → Maybe (Ļ„ ≔ τ′) → Maybe ((σ ⇒ Ļ„) ≔ (Ļƒā€² ⇒ τ′))
        f = Ī» { (just p) (just q) → just (trans (cong (_⇒ Ļ„) p) (cong (Ļƒā€² ⇒_) q))
              ; _ _ → nothing }
  ι       ==T ι         = just refl
  o       ==T o         = just refl
  _       ==T _         = nothing

  _==V_ : {σ Ļ„ : Types} → š’± σ → š’± Ļ„ → Maybe (σ ≔ Ļ„)
  var i σ ==V var i′ Ļ„ = 
    if i == i′ then σ ==T Ļ„ else nothing
\end{code}