Working System
This chapter stays in untyped lambda encodings of naturals (Church numerals), executed as Python functions.
5. Church Numerals and Arithmetic#
Goal. Represent natural numbers as higher-order functions and build arithmetic operators.
You will learn
Church numerals as iterators and how to convert to/from Python integers
How successor, addition, and multiplication are definable as lambda terms
How pairs let you implement predecessor by state-passing iteration
How to build basic predicates such as
is_zeroandleqHow to validate algebraic laws by small finite checks
Roadmap#
Define Church numerals and conversions (
church,to_int,from_int).Implement
succ,add, andmuland test them on small inputs.Implement Church pairs and use them to define
pred.Build basic predicates (
is_zero,leq) from arithmetic.Validate laws (associativity, distributivity) by computation.
Definition (Church Numerals)
A natural number n is encoded as a function that applies another function n times.
n ≡ λf. λx. f^n(x)
def church(n):
return lambda f: (lambda x: _iterate(f, x, n))
def _iterate(f, x, n):
for _ in range(n):
x = f(x)
return x
def to_int(n):
return n(lambda k: k + 1)(0)
zero = church(0)
one = church(1)
two = church(2)
three = church(3)
Definition (Successor)
succ n ≡ λf. λx. f (n f x).
succ = lambda n: (lambda f: (lambda x: f(n(f)(x))))
def from_int(n):
current = zero
for _ in range(n):
current = succ(current)
return current
Definition (Addition and Multiplication)
add m n ≡ λf. λx. m f (n f x)mul m n ≡ λf. m (n f)
The multiplication form is eta-short. It is eta-equivalent to the fully expanded
λf. λx. m (n f) x.
add = lambda m: (lambda n: (lambda f: (lambda x: m(f)(n(f)(x)))))
mul = lambda m: (lambda n: (lambda f: m(n(f))))
pow = lambda b: (lambda e: e(b))
print(to_int(add(two)(three)))
print(to_int(mul(two)(three)))
print(to_int(pow(two)(three)))
5
6
8
Definition (Pairs and Predecessor)
Predecessor is trickier. We use pairs to carry a “previous” value while iterating.
pair = lambda a: (lambda b: (lambda f: f(a)(b)))
fst = lambda p: p(lambda a: (lambda b: a))
snd = lambda p: p(lambda a: (lambda b: b))
def pred(n):
def step(p):
return pair(snd(p))(succ(snd(p)))
start = pair(zero)(zero)
return fst(n(step)(start))
sub = lambda m: (lambda n: n(pred)(m))
print(to_int(pred(three)))
print(to_int(sub(three)(two)))
2
1
Exercise
Define
is_zerousing Church booleans.Implement
leq m n(m <= n) using subtraction andis_zero.Show that
addis associative by testing on a small range of numbers.Show that
muldistributes overaddby testing on a small range of numbers. See solution: Exercise 5 (Church Numerals)
Summary#
A Church numeral is an iterator: it applies a function
ntimes.succ,add, andmulcan be defined purely by function composition and iteration.Predecessor is defined by carrying state through an iteration (pairs).
Predicates like
is_zeroand comparisons likeleqcan be built from these encodings.Operationally: build confidence by testing small ranges, then use induction chapters for fully general proofs.
Next: recursion via fixpoints and how to make Church-style recursion work in eager Python (Chapter 6).