module Realisability.Data.Nat {β} (πΈ : PCA β) where
open Realisability.PCA.Fixpoint πΈ
open Realisability.PCA.Sugar πΈ
open Realisability.Data.Pair πΈ
open Realisability.Data.Bool πΈ
private variable
: β― β πΈ β f g x y z
Natural numbers in a PCAπ
We define an encoding of natural numbers in a partial combinatory
algebra using Curry numerals, which uses the
encoding of booleans in a PCA and pairs in a PCA. The number zero is
simply the identity function, and the successor of a number is given by
pairing `false
with that number.
The first component of the pair thus encodes whether the number is
zero.
: β―βΊ πΈ
`zero = val β¨ x β© x
`zero
: β―βΊ πΈ
`suc = val β¨ x β© `false `, x `suc
Note that while the identity function may not look like a
pair, since in our encoding projection from
is implemented by applying
itself to either `true
(for
the first component) or `false
(for
the second), the identity function actually behaves extensionally like
the pairing of `true
and `false
.
: β―βΊ πΈ
`iszero = `fst `iszero
By recursion we can encode any number as a value of
: Nat β β―βΊ πΈ
`num = `zero
`num zero (suc x) = record
`num { fst = `pair β `false β `num x
; snd = `pairββ (absβ _ _) (`num x .snd)
}
We can define the predecessor function succinctly using a conditional:
: β―βΊ πΈ
`pred = val β¨ x β© `if (`fst `Β· x) then `zero else (`snd `Β· x) `pred
The usual arguments show that these functions all compute as expected.
abstract
: β x β `num (suc x) .fst β‘ `suc β `num x
`num-suc = sym (abs-Ξ² _ _ (`num x))
`num-suc x
: β x β β β `suc β x β
`sucββ = subst β_β (sym (abs-Ξ²β [] ((_ , ah) β· []))) (`pairββ (`false .snd) ah)
`sucββ ah
: `iszero β `zero β‘ `true .fst
`iszero-zero = abs-Ξ² _ _ `zero β abs-Ξ² _ _ (_ , absβ _ _)
`iszero-zero
: β x β β `iszero β (`suc β x) β‘ `false .fst
`iszero-suc {x} xh =
`iszero-suc (`suc β x) β‘β¨ ap (`iszero β_) (abs-Ξ² _ _ (_ , xh)) β©
`iszero β (`pair β `false β x) β‘β¨ `fst-Ξ² (`false .snd) xh β©
`iszero β .fst β
`false
: `pred β `zero β‘ `zero .fst
`pred-zero =
`pred-zero _ _ `zero β©
`pred β `zero β‘β¨ abs-Ξ² (`snd β `zero) β‘β¨ ap (Ξ» e β e β `zero β (`snd β `zero)) (`iszero-zero) β©
β `fst β `zero β β `zero β (`snd β `zero) β‘β¨ abs-Ξ²β [] ((_ , subst β_β (sym remβ) (absβ _ _)) β· `zero β· []) β©
`true β `zero β .fst β
`zero where
: `snd β `zero β‘ `false .fst
remβ = abs-Ξ² _ _ `zero β abs-Ξ² _ _ `false
remβ
: β x β β `pred β (`suc β x) β‘ x
`pred-suc {x} xh =
`pred-suc (`suc β x) β‘β¨ abs-Ξ² _ _ (_ , `sucββ xh) β©
`pred β (`suc β x) β β `zero β (`snd β (`suc β x)) β‘β¨ ap (Ξ» e β e β `zero β (`snd β (`suc β x))) (ap (`fst β_) (abs-Ξ² _ _ (_ , xh)) β `fst-Ξ² (`false .snd) xh) β©
β `fst β (`suc β x) β β‘β¨ ap (Ξ» e β (`false β `zero) β e) (ap (`snd β_) (abs-Ξ² _ _ (_ , xh)) β `snd-Ξ² (`false .snd) xh) β©
`false β `zero β β `snd β ((_ , xh) β· `zero β· []) β©
`false β `zero β x β‘β¨ abs-Ξ²β [] x β
Primitive recursionπ
We define a recursor for natural numbers using the `Z
fixed-point combinator. This will be a
program
which satisfies
First we define a worker function which is parametrised over both the
βrecursive referenceβ and all the arguments of the recursor (the zero
and successor βcasesβ and the number itself). We can then apply `Z
to everything to βtie the knotβ.
Note that, to ensure everything is properly defined, our `worker
function produces cases that take
an extra dummy argument; and our invocation of both its fixed point and
its βrecursive referenceβ pass `zero
to get rid of this.
private
: β―βΊ πΈ
`worker = val β¨ rec β© β¨ zc β© β¨ sc β© β¨ num β©
`worker (`iszero `Β· num)
`if (`true `Β· zc)
then (β¨ y β© sc `Β· (`pred `Β· num) `Β· (rec `Β· zc `Β· sc `Β· (`pred `Β· num) `Β· `zero))
else
: β―βΊ πΈ
`primrec = val β¨ z β© β¨ s β© β¨ n β© `Z `Β· `worker `Β· z `Β· s `Β· n `Β· `zero `primrec
The typical PCA calculation fanfare shows us that `primrec
is defined when applied to both
one and two arguments, and that it computes as stated.
abstract
: β z β β β `primrec β z β
`primrecββ = subst β_β (sym (abs-Ξ²β [] ((_ , zh) β· []))) (absβ _ _)
`primrecββ zh
: β z β β β f β β β `primrec β z β f β
`primrecββ = subst β_β (sym (abs-Ξ²β [] ((_ , fh) β· (_ , zh) β· []))) (absβ _ _)
`primrecββ zh fh
: β z β β β f β β `primrec β z β f β `zero β‘ z
`primrec-zero {z} {f} zh fh =
`primrec-zero (`zero β· (_ , fh) β· (_ , zh) β· []) β©
`primrec β z β f β `zero β‘β¨ abs-Ξ²β [] (Ξ» e β e β f β `zero β `zero) (`Z-Ξ² (`worker .snd) zh) β©
β `Z β `worker β z β β f β `zero β `zero β‘β¨ ap (`Z β `worker) β z β f β `zero β β `zero β‘β¨ ap (Ξ» e β e β `zero) (abs-Ξ²β [] (`zero β· (_ , fh) β· (_ , zh) β· (_ , `Zββ (`worker .snd)) β· [])) β©
β `worker β (`true β z) β % _ % `zero .fst β‘β¨ apβ _%_ (apβ _%_ (apβ _%_ `iszero-zero refl) refl β `true-Ξ² (`trueββ zh) (absβ _ _)) refl β©
β `iszero β `zero β .fst β‘β¨ `true-Ξ² zh (`zero .snd) β©
`true β z β `zero
z β
: β z β β β f β β β x β β `primrec β z β f β (`suc β x) β‘ f β x β (`primrec β z β f β x)
`primrec-suc {z} {f} {x} zh fh xh =
`primrec-suc (`suc β x) β‘β¨ abs-Ξ²β [] ((_ , `sucββ xh) β· (_ , fh) β· (_ , zh) β· []) β©
`primrec β z β f β (`suc β x) β `zero β‘β¨ ap (Ξ» e β e β f β (`suc β x) β `zero) (`Z-Ξ² (`worker .snd) zh) β©
β `Z β `worker β z β β f β (`Z β `worker) β z β f β (`suc β x) β `zero β‘β¨ ap (Ξ» e β e % `zero .fst) (abs-Ξ²β [] ((_ , `sucββ xh) β· (_ , fh) β· (_ , zh) β· (_ , `Zββ (`worker .snd)) β· [])) β©
`worker β (`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 β· []) β©
`iszero β (`suc β x) % `Z β `worker β z β f β (`pred β (`suc β x)) β `zero β‘β¨ ap (Ξ» e β f % e % `Z β `worker β z β f β e β `zero) (`pred-suc xh) β©
f % `pred β (`Z β `worker β z β f β x β `zero) β‘β¨ apβ _%_ refl (sym (abs-Ξ²β [] ((_ , xh) β· (_ , fh) β· (_ , zh) β· []))) β©
f β x β (`primrec β z β f β x) β f β x β