Tom de Jong & Martin Escardo, 20 May 2019.

Combinatory version of Platek-Scott-Plotkin PCF.
Includes (reflexive transitive closure of) operational semantics.

\begin{code}

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

open import UF.PropTrunc

module PCF.Combinatory.PCF (pt : propositional-truncations-exist) where

open PropositionalTruncation pt

open import MLTT.Spartan
open import UF.Subsingletons

data type : 𝓤₀ ̇ where
  ι   : type
  _⇒_ : type  type  type

infixr 1 _⇒_

data PCF : (σ : type)  𝓤₀ ̇ where
  Zero   : PCF ι
  Succ   : PCF (ι  ι)
  Pred   : PCF (ι  ι)
  ifZero : PCF (ι  ι  ι  ι)
  Fix    : {σ : type}      PCF ((σ  σ)  σ)
  K      : {σ τ : type}    PCF (σ  τ  σ)
  S      : {ρ σ τ : type}  PCF ((ρ  σ  τ)  (ρ  σ)  ρ  τ)
  _·_    : {σ τ : type}    PCF (σ  τ)  PCF σ  PCF τ

infixl 1 _·_

⌜_⌝ :   PCF ι
 zero  = Zero
 succ n  = Succ ·  n 

data _▹'_ : {σ : type}  PCF σ  PCF σ  𝓤₀ ̇ where
  Pred-zero   : (Pred · Zero) ▹' Zero
  Pred-succ   : (n : )  (Pred ·  succ n ) ▹'  n 
  ifZero-zero : (s t : PCF ι)  (ifZero · s · t · Zero) ▹' s
  ifZero-succ : (n : ) (s t : PCF ι)  (ifZero · s · t ·  succ n ) ▹' t
  Fix-step    : {σ : type} (t : PCF (σ  σ))  (Fix · t) ▹' (t · (Fix · t))
  K-step      : {σ τ : type} (s : PCF σ) (t : PCF τ)  (K · s · t) ▹' s
  S-step      : {ρ σ τ : type} (f : PCF (ρ  σ  τ)) (g : PCF (ρ  σ)) (x : PCF ρ) 
                (S · f · g · x) ▹' (f · x · (g · x))
  ·-step      : {σ τ : type} (s t : PCF (σ  τ)) (r : PCF σ) 
                s ▹' t  (s · r) ▹' (t · r)
  Pred-arg    : (s t : PCF ι)  s ▹' t  (Pred · s) ▹' (Pred · t)
  Succ-arg    : (s t : PCF ι)  s ▹' t  (Succ · s) ▹' (Succ · t)
  ifZero-arg  : (s t r r' : PCF ι) 
                r ▹' r'  (ifZero · s · t · r) ▹' (ifZero · s · t · r')

_▹_ : {σ : type}  PCF σ  PCF σ  𝓤₀ ̇
s  t =  s ▹' t 

data _▹*'_ : {σ : type}  PCF σ  PCF σ  𝓤₀ ̇ where
  extend : {σ : type} {s t : PCF σ}  s  t  s ▹*' t
  refl   : {σ : type} (s : PCF σ)  s ▹*' s
  trans  : {σ : type} {s t r : PCF σ}  s ▹*' t  t ▹*' r  s ▹*' r

_▹*_ : {σ : type}  PCF σ  PCF σ  𝓤₀ ̇
s ▹* t =  s ▹*' t 

▹'-to-▹*' : {σ τ : type} (f : PCF σ  PCF τ) 
            ((s t : PCF σ)  s ▹' t  (f s) ▹' (f t)) 
            (s t : PCF σ)  s ▹*' t  (f s) ▹*' (f t)
▹'-to-▹*' f f-preserves-▹' s t (extend rel) = extend (∥∥-rec a b rel)
 where
  a : is-prop (f s  f t)
  a = ∥∥-is-prop
  b : (step : s ▹' t)   f s ▹' f t 
  b step =  f-preserves-▹' s t step 

▹'-to-▹*' f f-preserves-▹' s s (refl s) = refl (f s)
▹'-to-▹*' f f-preserves-▹' s r (trans {σ} {s} {t} {r} rel₁ rel₂) = trans IH₁ IH₂
 where
  IH₁ : f s ▹*' f t
  IH₁ = ▹'-to-▹*' f f-preserves-▹' s t rel₁
  IH₂ : f t ▹*' f r
  IH₂ = ▹'-to-▹*' f f-preserves-▹' t r rel₂

▹'-to-▹* : {σ τ : type} (f : PCF σ  PCF τ) 
           ((s t : PCF σ)  s ▹' t  (f s) ▹' (f t)) 
           (s t : PCF σ)  s ▹* t  (f s) ▹* (f t)
▹'-to-▹* f f-preserves-▹' s t = ∥∥-functor (▹'-to-▹*' f f-preserves-▹' s t)

·-step* : {σ τ : type} (f g : PCF (σ  τ)) (t : PCF σ)
         f ▹* g  (f · t) ▹* (g · t)
·-step* f g t rel = ▹'-to-▹*  x  x · t)  f' g'  ·-step f' g' t) f g rel

Succ-arg* : (s t : PCF ι)  s ▹* t  (Succ · s) ▹* (Succ · t)
Succ-arg* = ▹'-to-▹*  x  Succ · x) Succ-arg

Pred-arg* : (s t : PCF ι)  s ▹* t  (Pred · s) ▹* (Pred · t)
Pred-arg* = ▹'-to-▹*  x  Pred · x) Pred-arg

ifZero-arg* : (s t r r' : PCF ι)  r ▹* r'
             (ifZero · s · t · r) ▹* (ifZero · s · t · r')
ifZero-arg* s t = ▹'-to-▹*  x  ifZero · s · t · x) (ifZero-arg s t)

\end{code}