I'm reading The Little Schemer and feel confused about the following code:
((lambda (len)
(lambda (l)
(cond
((null? l) 0)
(else
(+ 1 (len (cdr l)))))))
eternity)
(define eternity
(lambda (x)
(eternity x)))
The code is to determine the empty list, otherwise it never stops.
Why is the "len
" not recursion?
Although it can be dangerous to apply textual substitution to Lisp forms (since there are dangers of multiple evaluation, etc.), in this case it may help to look at this form and see how it fits together:
is an application, i.e., a function call. The function getting called takes one argument, called
len
, and returns another function that takes a single argumentl
. The function getting called is called witheternity
. When the call completes, the result is this function:Now, this function takes a list
l
and if it's empty, returns0
. Otherwise, it computes(cdr l)
(the rest of the list), and callseternity
with that value. When that returns,1
is added to the result, and that's the return value of the whole function. The problem, of course, is thateternity
which could also be written as
simply takes an argument
x
, and then callseternity
withx
. That's an infinite loop. In the above, I wrote "When that returns", but in fact,(eternity (cdr l))
never returns. So,is a function call that returns a function
(lambda (l) …)
that returns0
if called with an empty list, and goes into an infinite loop with a non-empty list.From a program analysis side of things, it's worth noting that there are other values for which this won't go into an infinite loop. For instance, if you call it with a string, then
(cdr l)
will be an error.Like you say, this is a definition of a length function as a partial function where it only completes for the empty list. But this hasn't gotten to the y-combinator part yet, it isn't an example of an anonymous function calling itself.
l
is a list of atoms, it is the argument to the function returned when(lambda (len) ...)
is evaluated.len
is a function passed into the outer lambda as an argument.The outer expression creates a lambda with
eternity
passed in as its argument. The outer lambda returns a function created by evaluating the inner lambda, the returned function is the thing that takeseternity
as an argument.If the code is passed an empty list (meaning wrap the whole first part followed by a
'()
in another set of parens) then it will evaluate to 0, of course.len
never gets evaluated.If the code is passed a nonempty lat then it will try to evaluate the
len
argument and you get an infinite recursion.