I'm working my way through SICP, and it gives the following definition for zero for Church Numerals:
(define zero (lambda (f) (lambda (x) x)))
I have a few questions about that:
Why the complicated syntax? It seems to be quite readable by just having the following instead:
(define (zero f) (lambda (x) x))where we can see it's a function called
zerothat takes one (unused) argumentfand returns a function-of-one-parameter that will return its parameter. It almost seems like the definition is just intended to be as non-straightforward as possible.What is the
xthere for? For example doing something like:((zero square) 100)returns
100. Isxjust the default value returned?
There is no
xin(lambda (x) x). None.The
xin(lambda (x) x)is bound. It could be named by any name whatever. We can not talk aboutxin(lambda (x) x)any more than we could talk aboutyin(lambda (y) y).There is no
yin(lambda (y) y)to speak of. It is just a placeholder, an arbitrary name whose sole purpose in the body is to be the same as in the binder. Same, without regard for which specific name is used there as long as it is used twice -- first time in the binder, and the other time in the body.And in fact there is this whole 'nother notation for lambda terms, called De Bruijn notation, where the same whole thing is written
(lambda 1). With1meaning, "I refer to the argument which the binder 1 step above me receives".So
xis unimportant. What's important is(lambda (x) x)which denotes a function which returns its argument as is. The so called "identity" function.But even this is not important here. The Church encoding of a number is really a binary function, a function expecting two arguments -- the
fand thez. The "successor step" unary functionfand the "zero" "value"z, whatever that might be, as long as the two go together. Make sense together. Work together.So how come we see two unary functions there when it is really one binary function in play?
That is the important bit. It is known as currying.
In lambda calculus all functions are unary. And to represent a binary function an unary function is used, such that when given its (first) argument it returns another unary function, which, when given its (now, second) argument, performs whatever thing our intended binary function ought to perform, using those two arguments, the first and the second.
This is all very very simple if we just write it in combinatory (equational) notation instead of the lambda notation:
where every juxtaposition denotes an application, and all applications associate on the left, so we imagine the above being a shortcut notation for
but it's the same thing. The differences in notation are not important.
And of course there is no
oneinlambda one. (lambda f. (lambda z. f (one f z) )). It is bound. It could just be named, I dunno,number:meaning,
(succ number)is such a number, which, given thefand thez, does with them one morefstep compared to whatnumberwould do.And so,
((zero square) 100)means, use the numberzerowith the successor stepsquareand the zero value of100, and havezeroperform its number of successor steps for us -- that is to say, 0 steps -- starting from the zero value. Thus returning it unchanged.Another possible use is
((zero (lambda (x) 0)) 1), or in generalwhich is just another way of writing
Hopefully you can see what
foois, easily. And also how to read aloud thistand thisf. (Probably the originalfwould be better nameds, for "successor", or something like that).