A natural numbers object in a cartesian category is an object with two arrows — the introduction rules —
(“zero” and “successor”; is recursive: its source is itself) such that for every object and pair , there is a unique with
This elimination rule is primitive recursion: is the sequence , . Uniqueness says contains nothing but — no numbers “before, after, or in between” (adding a would allow two ‘s generated by the same ).
Sources: DaoFP Chapter 7 (“Recursion”, §7.1 “Natural Numbers”: introduction rules, elimination rules, “In Programming”), §12 (as the Initial Algebra of ), §11 (the induction principle as dependent elimination); 7 Sketches Example 3.13 ( as the free category on one loop), Exercise 6.7 ( as initial rig); Kittenlab Lecture 5.
- Not every arrow is recursive — an arbitrary such arrow contains infinite information; the recursive ones are enough to define . This is the Peano encoding; in Haskell
data Nat = Z | S Nat, used mostly for type-level naturals. - is the Initial Algebra of the Endofunctor ; is the catamorphism (Lambek: ).
- The recursor
rec init stepimplements all primitive recursive functions, e.g.plus n = rec n S; curried addition usesinit = id,step = (S .)(DaoFP Exercise 7.1.2). Iteration in imperative languages is the same thing; compilers turn one into the other (tail-recursion optimization). - Lists generalize : (base-one numerals, DaoFP Exercise 7.2.1). A stronger elimination rule — the induction principle — needs dependent types.
Docs: ThCategory (GATlab) · Theories & presentations — Kittenlab Lecture 5
# the recursor: a mapping out of ℕ from init and step
rec(init, step) = n -> n == 0 ? init : step(rec(init, step)(n - 1))
plus(n) = rec(n, x -> x + 1)
plus(3)(4) # 7
double = rec(0, x -> x + 2); double(5) # 10Catlab version (run in a fresh Julia session — Catlab exports its own compose, id, FinFunction, …):
# Catlab: ℕ as the free category on one object and one generating loop
using Catlab
@present NatCat(FreeCategory) begin N::Ob; S::Hom(N, N) endimport Mathlib
#check @Nat.rec -- the eliminator (dependent: induction principle)
#check @Nat.zero
#check @Nat.succ
#check @Nat.iterate -- f^[n] : primitive recursion with init = x, step = f
example : (fun n => Nat.rec (motive := fun _ => ℕ) 3 (fun _ acc => acc + 1) n) 4 = 7 := by decidedata Nat where
Z :: Nat
S :: Nat -> Nat
rec :: a -> (a -> a) -> (Nat -> a) -- the recursor / elimination rule
rec init step = \n -> case n of
Z -> init
(S m) -> step (rec init step m)
plus :: Nat -> Nat -> Nat
plus n = rec n S -- init = n, step = S
plus' :: Nat -> Nat -> Nat -- inlined recursor
plus' n m = case m of
Z -> n
(S k) -> S (plus' k n)