Page:AIM-453.djvu/20

There was a problem when proofreading this page.

Steele and Sussman

18

The Art of the Interpreter


Local Procedures

We now have the ability to define and use the MAPCAR procedure. After some more experience in programming, however, we find that, having abstracted the common pattern from our loops, that the remaining part (the functional argument) tends to be different for each invocation of MAPCAR. Unfortunately, our language for all practical purposes requires that we use a name to refer to the functional arguments, because the only way we have to denote new procedures is to DEFINE names for them. We soon tire of thinking up new unique names for trivial procedures:

(DEFINE (FOOBAR-43 X) (* (+ X 4) 3))
... (MAPCAR FOOBAR-43 L)

We run the risk of name conflicts; also, it would be nice to be able to write the procedure definition at the single point of use.

More abstractly, given that procedures have become referenceable objects in the language, it would be nice to have a notation for them as objects, or rather a way to write an S-expression in code that would evaluate to a procedure. LISP [LISP 1M] adapted such a notation from the λ-calculus of Alonzo Church [Church]:

(LAMBDA <variables> <body>)

Comparing this with the DEFINE notation, we see that it has the same parts: a keyword so that it can be recognized; a list of parameters; and a body. The only difference is the omission of an irrelevant name. It is just the right thing.

Given this, we can simply write

(MAPCAR (LAMBDA (X) (* X X)) L)

rather than having to define SQUARE as a separate procedure. An additional benefit is that this notation makes it very easy for a compiler to examine this code and produce an efficient iterative implementation, because all the relevant code is present locally (assuming the compiler knows about MAPCAR).

Installing this notation requires only a two-line change in EVAL (see Figure 6).