open import 1Lab.Prelude

open import Data.Partial.Total
open import Data.Partial.Base
open import Data.Vec.Base

open import Realisability.PCA

import Realisability.PCA.Fixpoint
import Realisability.Data.Pair
import Realisability.PCA.Sugar
module Realisability.Data.Nat {β„“} (𝔸 : PCA β„“) where
open Realisability.PCA.Fixpoint 𝔸
open Realisability.PCA.Sugar 𝔸
open Realisability.Data.Pair 𝔸

Natural numbers in a PCAπŸ”—

`zero : ↯⁺ 𝔸
`zero = val ⟨ x ⟩ x

`suc : ↯⁺ 𝔸
`suc = val ⟨ x ⟩ `pair `· `false `· x

`num : Nat β†’ ↯⁺ 𝔸
`num zero    = `zero
`num (suc x) = record
  { fst = `pair ⋆ `false ⋆ `num x
  ; snd = `pair↓₂ (abs↓ _ _) (`num x .snd)
  }

`pred : ↯⁺ 𝔸
`pred = val ⟨ x ⟩ `fst `· x `· `zero `· (`snd `· x)

`iszero : ↯⁺ 𝔸
`iszero = `fst

private
  variable f g x y z : β†― ⌞ 𝔸 ⌟

  `worker : ↯⁺ 𝔸
  `worker = val ⟨ rec ⟩ ⟨ zc ⟩ ⟨ sc ⟩ ⟨ num ⟩
    `iszero `Β· num
      `Β· (`true `Β· zc)
      `· (⟨ y ⟩ sc `· (`pred `· num) `· (rec `· zc `· sc `· (`pred `· num) `· `zero))

`primrec : ↯⁺ 𝔸
`primrec = val ⟨ z ⟩ ⟨ s ⟩ ⟨ n ⟩ `Z `· `worker `· z `· s `· n `· `zero

abstract
  `num-suc : βˆ€ x β†’ `num (suc x) .fst ≑ `suc ⋆ `num x
  `num-suc x = sym (abs-Ξ² _ _ (`num x))

  `suc↓₁ : βˆ€ {a} β†’ ⌞ a ⌟ β†’ ⌞ `suc .fst % a ⌟
  `suc↓₁ ah = subst ⌞_⌟ (sym (abs-Ξ²β‚™ [] ((_ , ah) ∷ []))) (`pair↓₂ (`false .snd) ah)

  `iszero-zero : `iszero ⋆ `zero ≑ `true .fst
  `iszero-zero = abs-Ξ² _ _ `zero βˆ™ abs-Ξ² _ _ (_ , abs↓ _ _)

  `iszero-suc : ⌞ x ⌟ β†’ `iszero ⋆ (`suc ⋆ x) ≑ `false .fst
  `iszero-suc {x} xh =
    `iszero ⋆ (`suc ⋆ x)           β‰‘βŸ¨ ap (`iszero ⋆_) (abs-Ξ² _ _ (_ , xh)) ⟩
    `iszero ⋆ (`pair ⋆ `false ⋆ x) β‰‘βŸ¨ `fst-Ξ² (`false .snd) xh ⟩
    `false .fst                    ∎

  `pred-zero : `pred ⋆ `zero ≑ `zero .fst
  `pred-zero =
    `pred ⋆ `zero                             β‰‘βŸ¨ abs-Ξ² _ _ `zero ⟩
    ⌜ `fst ⋆ `zero ⌝ ⋆ `zero ⋆ (`snd ⋆ `zero) β‰‘βŸ¨ ap! (`iszero-zero) ⟩
    `true ⋆ `zero ⋆ (`snd ⋆ `zero)            β‰‘βŸ¨ abs-Ξ²β‚™ [] ((_ , subst ⌞_⌟ (sym rem₁) (abs↓ _ _)) ∷ `zero ∷ []) ⟩
    `zero .fst                                ∎
    where
      rem₁ : `snd ⋆ `zero ≑ `false .fst
      rem₁ = abs-Ξ² _ _ `zero βˆ™ abs-Ξ² _ _ `false

  `pred-suc : ⌞ x ⌟ β†’ `pred ⋆ (`suc ⋆ x) ≑ x
  `pred-suc {x} xh =
    `pred ⋆ (`suc ⋆ x)                                   β‰‘βŸ¨ abs-Ξ² _ _ (_ , `suc↓₁ xh) ⟩
    ⌜ `fst ⋆ (`suc ⋆ x) ⌝ ⋆ `zero ⋆ (`snd ⋆ (`suc ⋆ x))  β‰‘βŸ¨ ap! (ap (`fst ⋆_) (abs-Ξ² _ _ (_ , xh)) βˆ™ `fst-Ξ² (`false .snd) xh) ⟩
    `false ⋆ `zero ⋆ ⌜ `snd ⋆ (`suc ⋆ x) ⌝               β‰‘βŸ¨ ap! (ap (`snd ⋆_) (abs-Ξ² _ _ (_ , xh)) βˆ™ `snd-Ξ² (`false .snd) xh) ⟩
    `false ⋆ `zero ⋆ x                                   β‰‘βŸ¨ abs-Ξ²β‚™ [] ((_ , xh) ∷ `zero ∷ []) ⟩
    x                                                    ∎

  `primrec-zero : ⌞ z ⌟ β†’ ⌞ f ⌟ β†’ `primrec ⋆ z ⋆ f ⋆ `zero ≑ z
  `primrec-zero {z} {f} zh fh =
    `primrec ⋆ z ⋆ f ⋆ `zero                                     β‰‘βŸ¨ abs-Ξ²β‚™ [] (`zero ∷ (_ , fh) ∷ (_ , zh) ∷ []) ⟩
    ⌜ `Z ⋆ `worker ⋆ z ⌝ ⋆ f ⋆ `zero ⋆ `zero                     β‰‘βŸ¨ ap! (`Z-Ξ² (`worker .snd) zh) ⟩
    ⌜ `worker ⋆ (`Z ⋆ `worker) ⋆ z ⋆ f ⋆ `zero ⌝ ⋆ `zero         β‰‘βŸ¨ ap (Ξ» e β†’ e % `zero .fst) (abs-Ξ²β‚™ [] (`zero ∷ (_ , fh) ∷ (_ , zh) ∷ (_ , `Z↓₁ (`worker .snd)) ∷ [])) ⟩
    ⌜ `iszero ⋆ `zero ⋆ (`true ⋆ z) ⌝ % _ % `zero .fst           β‰‘βŸ¨ apβ‚‚ _%_ (apβ‚‚ _%_ (apβ‚‚ _%_ `iszero-zero refl) refl βˆ™ `true-Ξ² (`true↓₁ zh) (abs↓ _ _)) refl ⟩
    `true ⋆ z ⋆ `zero .fst                                       β‰‘βŸ¨ `true-Ξ² zh (`zero .snd) ⟩
    z                                                            ∎

  `primrec-suc : ⌞ z ⌟ β†’ ⌞ f ⌟ β†’ ⌞ x ⌟ β†’ `primrec ⋆ z ⋆ f ⋆ (`suc ⋆ x) ≑ f ⋆ x ⋆ (`primrec ⋆ z ⋆ f ⋆ x)
  `primrec-suc {z} {f} {x} zh fh xh =
    `primrec ⋆ z ⋆ f ⋆ (`suc ⋆ x)                                                 β‰‘βŸ¨ abs-Ξ²β‚™ [] ((_ , `suc↓₁ xh) ∷ (_ , fh) ∷ (_ , zh) ∷ []) ⟩
    ⌜ `Z ⋆ `worker ⋆ z ⌝ ⋆ f ⋆ (`suc ⋆ x) ⋆ `zero                                 β‰‘βŸ¨ ap! (`Z-Ξ² (`worker .snd) zh) ⟩
    `worker ⋆ (`Z ⋆ `worker) ⋆ z ⋆ f ⋆ (`suc ⋆ x) ⋆ `zero                         β‰‘βŸ¨ ap (Ξ» e β†’ e % `zero .fst) (abs-Ξ²β‚™ [] ((_ , `suc↓₁ xh) ∷ (_ , fh) ∷ (_ , zh) ∷ (_ , `Z↓₁ (`worker .snd)) ∷ [])) ⟩
    `iszero ⋆ (`suc ⋆ x) ⋆ (`true ⋆ z) % _ % `zero .fst                           β‰‘βŸ¨ apβ‚‚ _%_ (apβ‚‚ _%_ (apβ‚‚ _%_ (`iszero-suc xh) refl) refl βˆ™ `false-Ξ² (`true↓₁ zh) (abs↓ _ _)) refl βˆ™ abs-Ξ²β‚™ ((`suc ⋆ x , `suc↓₁ xh) ∷ (f , fh) ∷ (z , zh) ∷ (`Z ⋆ `worker , `Z↓₁ (`worker .snd)) ∷ []) (`zero ∷ []) ⟩
    f % `pred ⋆ (`suc ⋆ x) % `Z ⋆ `worker ⋆ z ⋆ f ⋆ (`pred ⋆ (`suc ⋆ x)) ⋆ `zero  β‰‘βŸ¨ ap (Ξ» e β†’ f % e % `Z ⋆ `worker ⋆ z ⋆ f ⋆ e ⋆ `zero) (`pred-suc xh) ⟩
    f ⋆ x ⋆ (`Z ⋆ `worker ⋆ z ⋆ f ⋆ x ⋆ `zero)                                    β‰‘βŸ¨ apβ‚‚ _%_ refl (sym (abs-Ξ²β‚™ [] ((_ , xh) ∷ (_ , fh) ∷ (_ , zh) ∷ []))) ⟩
    f ⋆ x ⋆ (`primrec ⋆ z ⋆ f ⋆ x)                                                ∎