Next: Dynamic Binding, Previous: Lambda Expressions, Up: Special Forms [Contents][Index]

The binding constructs `let`

, `let*`

, `letrec`

,
`letrec*`

, `let-values`

, and `let*-values`

give Scheme
block structure, like Algol 60. The syntax of the first four
constructs is identical, but they differ in the regions they establish
for their variable bindings. In a `let`

expression, the initial
values are computed before any of the variables become bound; in a
`let*`

expression, the bindings and evaluations are performed
sequentially; while in `letrec`

and `letrec*`

expressions,
all the bindings are in effect while their initial values are being
computed, thus allowing mutually recursive definitions. The
`let-values`

and `let*-values`

constructs are analogous to
`let`

and `let*`

respectively, but are designed to handle
multiple-valued expressions, binding different identifiers to the
returned values.

- extended standard special form:
**let***((*`variable``init`) …) expr expr … -
The

`init`s are evaluated in the current environment (in some unspecified order), the`variable`s are bound to fresh locations holding the results, the`expr`s are evaluated sequentially in the extended environment, and the value of the last`expr`is returned. Each binding of a`variable`has the`expr`s as its region.MIT/GNU Scheme allows any of the

`init`s to be omitted, in which case the corresponding`variable`s are unassigned.Note that the following are equivalent:

(let ((

`variable``init`) …)`expr``expr`…) ((lambda (`variable`…)`expr``expr`…)`init`…)Some examples:

(let ((x 2) (y 3)) (* x y)) ⇒ 6

(let ((x 2) (y 3)) (let ((foo (lambda (z) (+ x y z))) (x 7)) (foo 4))) ⇒ 9

See Iteration, for information on “named

`let`

”.

- extended standard special form:
**let****((*`variable``init`) …) expr expr … -
`let*`

is similar to`let`

, but the bindings are performed sequentially from left to right, and the region of a binding is that part of the`let*`

expression to the right of the binding. Thus the second binding is done in an environment in which the first binding is visible, and so on.Note that the following are equivalent:

(let* ((

`variable1``init1`) (`variable2``init2`) … (`variableN``initN`))`expr``expr`…)(let ((

`variable1``init1`)) (let ((`variable2``init2`)) … (let ((`variableN``initN`))`expr``expr`…) …))An example:

(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ⇒ 70

- extended standard special form:
**letrec***((*`variable``init`) …) expr expr … -
The

`variable`s are bound to fresh locations holding unassigned values, the`init`s are evaluated in the extended environment (in some unspecified order), each`variable`is assigned to the result of the corresponding`init`, the`expr`s are evaluated sequentially in the extended environment, and the value of the last`expr`is returned. Each binding of a`variable`has the entire`letrec`

expression as its region, making it possible to define mutually recursive procedures.MIT/GNU Scheme allows any of the

`init`s to be omitted, in which case the corresponding`variable`s are unassigned.(letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88)) ⇒ #t

One restriction on

`letrec`

is very important: it shall be possible to evaluated each`init`without assigning or referring to the value of any`variable`. If this restriction is violated, then it is an error. The restriction is necessary because Scheme passes arguments by value rather than by name. In the most common uses of`letrec`

, all the`init`s are`lambda`

or`delay`

expressions and the restriction is satisfied automatically.

- extended standard special form:
**letrec****((*`variable``init`) …) expr expr … The

`variable`s are bound to fresh locations, each`variable`is assigned in left-to-right order to the result of evaluating the corresponding`init`(interleaving evaluations and assignments), the`expr`s are evaluated in the resulting environment, and the values of the last`expr`are returned. Despite the left-to-right evaluation and assignment order, each binding of a`variable`has the entire`letrec*`

expression as its region, making it possible to define mutually recursive procedures.If it is not possible to evaluate each

`init`without assigning or referring to the value of the corresponding`variable`or the`variable`of any of the bindings that follow it in`bindings`, it is an error. Another restriction is that it is an error to invoke the continuation of an`init`more than once.;; Returns the arithmetic, geometric, and ;; harmonic means of a nested list of numbers (define (means ton) (letrec* ((mean (lambda (f g) (f (/ (sum g ton) n)))) (sum (lambda (g ton) (if (null? ton) (+) (if (number? ton) (g ton) (+ (sum g (car ton)) (sum g (cdr ton))))))) (n (sum (lambda (x) 1) ton))) (values (mean values values) (mean exp log) (mean / /))))

Evaluating

`(means '(3 (1 4)))`

returns three values:`8/3`

,`2.28942848510666`

(approximately), and`36/19`

.

- standard special form:
**let-values***((*`formals``init`) …) expr expr … The

`init`s are evaluated in the current environment (in some unspecified order) as if by invoking`call-with-values`

, and the variables occurring in the`formals`are bound to fresh locations holding the values returned by the`init`s, where the`formals`are matched to the return values in the same way that the`formals`in a`lambda`

expression are matched to the arguments in a procedure call. Then, the`expr`s are evaluated in the extended environment, and the values of the last`expr`are returned. Each binding of a`variable`has the`expr`s as its region.It is an error if the

`formals`do not match the number of values returned by the corresponding`init`.(let-values (((root rem) (exact-integer-sqrt 32))) (* root rem)) ⇒ 35

- standard special form:
**let*-values***((*`formals``init`) …) expr expr … The

`let*-values`

construct is similar to`let-values`

, but the`init`s are evaluated and bindings created sequentially from left to right, with the region of the bindings of each`formals`including the`init`s to its right as well as`body`. Thus the second`init`is evaluated in an environment in which the first set of bindings is visible and initialized, and so on.(let ((a 'a) (b 'b) (x 'x) (y 'y)) (let*-values (((a b) (values x y)) ((x y) (values a b))) (list a b x y))) ⇒ (x y x y)

Next: Dynamic Binding, Previous: Lambda Expressions, Up: Special Forms [Contents][Index]