In case representing pairs as procedures wasn't mind-boggling enough, consider that, in a language that can manipulate procedures, we can get by without numbers (at least insofar as nonnegative integers are concerned) by implementing 0 and the operation of adding 1 as
(define zero (lambda (f) (lambda (x) x))) (define (add-1 n) (lambda (f) (lambda (x) (f ((n f) x)))))
This representation is known as Church numerals, after its inventor, Alonzo Church, the logician who invented the λ calculus.
Define
one
and two
directly (not in terms of zero
and add-1
). (Hint: Use substitution to evaluate (add-1 zero)
). Give a direct definition of the addition procedure +
(not in terms of repeated application of add-1
).Let's take the hint and run with it...
(add-1 zero) = (add-1 (lambda (f) (lambda (x) x))) = (lambda (f) (lambda (x) (f (((lambda (f) (lambda (x) x)) f) x)))) = (lambda (f) (lambda (x) (f ((lambda (x) x) x)))) = (lambda (f) (lambda (x) (f x)))That give us a definition for
one
:
(define one (lambda (f) (lambda (x) (f x))))And we can do the same to figure out
two
:
(add-1 one) = (add-1 (lambda (f) (lambda (x) (f x)))) = (lambda (f) (lambda(x) (f (((lambda (f) (lambda (x) (f x))) f) x)))) = (lambda (f) (lambda(x) (f (((lambda (x) (f x)) x)))) = (lambda (f) (lambda(x) (f (f x))))So
two
is:
(define two (lambda (f) (lambda (x) (f (f x)))))Looking at the pattern we can see that the Church numeral representation of the positive integer n is fn(x) (i.e. (f ο f ο…ο f ο f)(x), with n occurrences of f). Also, to assist with the remainder of the exercise, we should note that:
zero
produces a single-parameter lambda expression that ignores its parameter and returns a single-parameter lambda expression that returns its parameter. So we can convertzero
to its integer equivalent value using the expression((zero f) 0)
, wheref
is any value.one
produces a single-parameter,f
, lambda expression that returns a new single-parameter lambda expression that returns the results of applyingf
to its parameter. So, assuming we pass 0 as the parameter to the second lambda expression as withzero
, then we can convertone
to its integer equivalent value using the expression((one inc) 0)
, whereinc
is the increment procedure defined earlier.two
produces a single-parameter,f
, lambda expression that returns a new single-parameter lambda expression that returns the results of applyingf
to the results of applyingf
to its parameter. So similar toone
, we can converttwo
to its integer equivalent value using the expression((two inc) 0)
.
n
, we can convert it to its integer equivalent value using the expression ((n inc) 0)
. Here's a procedure that encapsulates this logic which we can use to allow easy testing of our work with Church numerals:
(define (unchurch n) ((n inc) 0))For example:
> (unchurch zero) 0 > (unchurch one) 1 > (unchurch two) 2Now onto defining
+
for Church numerals. We know that we want this to produce a valid Church numeral. I.e. a single-parameter lambda expression whose parameter, f
, is a procedure and that returns a single-parameter lambda expression. We also know that, given two Church numerals representing the nonnegative integers a and b, we want the evaluation of (((+ a b) f) x)
to apply f
repeatedly, starting with x
as the initial input, for a total of a+b times. How can we do this? Well evaluating ((a f) x)
will apply f
a total of a
times to whatever is passed to it as x
, and ((b f) x)
will apply f
a total of b
times to whatever is passed to it as x
. So we can produce a composite function that evaluates ((b f) x)
and then uses that as the value of x
for evaluating ((a f) x)
(or vice versa). Here's my definition
(define (+ a b) (lambda (f) (lambda (x) ((a f) ((b f) x)))))And to check it works:
> (unchurch (+ one two)) 3 > (unchurch (+ (+ one two) two)) 5Of course we can go much further with Church numerals - there's a whole raft of definitions for various computations. Just for fun I also defined
*
for Church numerals:
(define (* a b) (lambda (f) (lambda (x) ((a (b f)) x))))And here it is in action:
> (unchurch (* (+ one two) two)) 6 > (unchurch (* (+ two two) (+ one two))) 12 > (unchurch (* (* two two) (* one two))) 8
No comments:
Post a Comment