Is there some way to extend Scheme's repertoire of operations beyond the built-in procedures? I'd like to have a procedure to compute the square of any given integer, for instance.
If you can figure out how to perform a computation, you can write that knowledge into a Scheme procedure. Recall that in Scheme procedures are values. The built-in procedures are values of predefined variables. The procedures that you devise will be the values of lambda-expressions.
What do lambda-expressions look like?
Let's start with the simplest kind, which you use to express procedures that have only one possible arity (that is, procedures that take the same number of arguments whenever they are called). As an example, here's a lambda-expression that has the squaring procedure as its value:
A lambda expression of this kind begins with a left parenthesis and the keyword(lambda (root) (* root root))
lambda. After that, you get what is called a
parameter list -- a pair of parentheses enclosing a sequence of
variables, one for each operand of the procedure. Following the parameter
list is the body of the lambda-expression, which has the same
structure as the body of a let-expression -- zero or more internal
definitions, followed by one or more commands. At the very end, there is a
right parenthesis to match the initial left parenthesis.
The idea of the parameter list is that, since you don't know what the actual operand values for the procedure will be when it is called (and in fact the operands will no doubt be different in different calls), you need some kind of a placeholder to stand for each operand while you explain how the result of the procedure is computed from the operands. The first variable in the parameter list stands for the first of the operands that will be provided when the procedure is called, the second variable for the second operand, and so forth.
How do you call a procedure that is expressed in this way?
Just as you call any procedure: Form a procedure call by putting a left parenthesis to the left of the lambda-expression, argument expressions and a right parenthesis to its right. For example, to find the square of 1620, you could write:
> ((lambda (root)
(* root root))
1620)
2624400
It would be shorter just to write (* 1620 1620).
It's true that writing a lambda-expression doesn't make things any simpler in this particular case. However, you'll find that there are lots of contexts in Scheme in which it's helpful to be able to express not only built-in procedures, but those you construct yourself.
For instance?
For instance, in a definition:
(define square
(lambda (root)
(* root root)))
This definition makes the squaring procedure the value of the variable
square. Once Scheme has seen this definition, you can use
that variable in procedure calls, just as if it were predefined:
Are these procedure calls short enough for you?> (square 1620) 2624400 > (square (+ 2 (square 3))) 121
There are definite possibilities here. So if you have a long, complicated calculation that depends on the values of one or two variables, and you need to repeat it with different values of those variables, you could write the procedure once, give it a name, and then just call that procedure with the appropriate operands?
Exactly. Suppose you're supposed to evaluate the algebraic expression (x - 9)(3x + 4)(2x - 7) for several values of x -- say, x = -12, -8, -4, 0, 4, 8, 12. You could do it this way:
> (define poly
(lambda (x)
(* (- x 9)
(+ (* 3 x) 4)
(- (* 2 x) 7))))
> (poly -12)
-20832
> (poly -8)
-7820
> (poly -4)
-1560
> (poly 0)
252
> (poly 4)
-80
> (poly 8)
-252
> (poly 12)
2040
Are the variables in the parameter list bound globally or locally?
They are not bound at all until the procedure is actually called. At that point, they receive local bindings that are confined to the body of the lambda-expression (just as the bindings created in a let-expression are accessible only in the body of that expression). The values of the variables in the parameter list are the corresponding operands given in the call.
But what values do they have when the lambda-expression itself is evaluated?
They don't have any values -- they are simply placeholders until the operands arrive.
You may be assuming that when the lambda-expression itself is evaluated -- say, as part of a definition -- the body of that expression must be evaluated too. But Scheme does not need to evaluate the body of the procedure in order to construct the procedure as a value. Instead, Scheme builds an internal representation of the procedure body, called a closure, which contains all the information that will be needed when the body is ultimately evaluated. The closure still contains placeholders. Only when the procedure is called and the operand values arrive on the scene are the places filled, and only then is the body of the procedure evaluated.
Why are they called ``lambda-expressions''? Why was the keyword
lambda chosen?
The logician Alonzo Church, who was one of the first to study systems of notation in which procedure-like values could be easily defined, used the lower-case Greek letter lambda in his notation. This was around 1940, and people have simply followed the tradition he established ever since.
Next topic
Previous topic
Table of contents
This document is available on the World Wide Web as
http://www.math.grin.edu/~stone/scheme-web/lambda.html