\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}