Next: baselib expressions sequencing, Previous: baselib expressions derived cond, Up: baselib expressions [Index]
The binding constructs described in this section create local bindings
for variables that are visible only in a delimited region. The syntax
of the constructs let
, let*
, letrec
, and
letrec*
is identical, but they differ in the regions they
establish for their variable bindings and in the order in which the
values for the bindings are computed.
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.
letrec
or letrec*
expression, all the bindings are in
effect while their initial values are being computed, thus allowing
mutually recursive definitions.
letrec
expression, the initial values are computed before
being assigned to the variables; in a letrec*
, the evaluations
and assignments are performed sequentially.
In addition, the binding constructs let-values
and
let*-values
generalize let
and let*
to allow
multiple variables to be bound to the results of expressions that
evaluate to multiple values. They are analogous to let
and
let*
in the way they establish regions: in a let-values
expression, the initial values are computed before any of the variables
become bound; in a let*-values
expression, the bindings are
performed sequentially.
?bindings must have the form:
((?variable1 ?init1) …)
where each ?init is an expression, and ?body is as described in baselib bodies. Any variable must not appear more than once in the ?variables.
The ?inits are evaluated in the current environment (in some unspecified order), the ?variables are bound to fresh locations holding the results, the ?body is evaluated in the extended environment, and the values of the last expression of ?body are returned. Each binding of a ?variable has ?body as its region.
(let ((x 2) (y 3)) (* x y)) ⇒ 6 (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x))) ⇒ 35
See also named let
.
?bindings must have the form:
((?variable1 ?init1) …)
where each ?init is an expression, and ?body is as described in baselib bodies.
The let*
form is similar to let
, but the ?inits are
evaluated and bindings created sequentially from left to right, with the
region of each binding including the bindings to its right as well as
?body. Thus the second ?init is evaluated in an environment
in which the first binding is visible and initialized, and so on.
(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ⇒ 70
NOTE While the variables bound by a
let
expression must be distinct, the variables bound by alet*
expression need not be distinct.
?bindings must have the form:
((?variable1 ?init1) …)
where each ?init is an expression, and ?body is as described in baselib bodies. Any variable must not appear more than once in the ?variables.
The ?variables are bound to fresh locations, the ?inits are
evaluated in the resulting environment (in some unspecified order), each
?variable is assigned to the result of the corresponding
?init, the ?body is evaluated in the resulting environment,
and the values of the last expression in ?body are returned. Each
binding of a ?variable has the entire letrec
expression as
its region, making it possible to define mutually recursive procedures.
(letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88)) ⇒ #t
It should be possible to evaluate each ?init without assigning or
referring to the value of any ?variable. In the most common uses
of letrec
, all the ?inits are lambda
s and the
restriction is satisfied automatically. Another restriction is that the
continuation of each ?init should not be invoked more than once.
Implementation responsibilities: Implementations must detect
references to a ?variable during the evaluation of the ?init
expressions (using one particular evaluation order and order of
evaluating the ?init expressions). If an implementation detects
such a violation of the restriction, it must raise an exception with
condition type &assertion
. Implementations may or may not detect
that the continuation of each ?init is invoked more than once.
However, if the implementation detects this, it must raise an exception
with condition type &assertion
.
?bindings must have the form:
((?variable1 ?init1) …)
where each ?init is an expression, and ?body is as described in baselib bodies. Any variable must not appear more than once in the ?variables.
The ?variables are bound to fresh locations, each ?variable
is assigned in left–to–right order to the result of evaluating the
corresponding ?init, the ?body is evaluated in the resulting
environment, and the values of the last expression in ?body 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.
(letrec* ((p (lambda (x) (+ 1 (q (- x 1))))) (q (lambda (y) (if (zero? y) 0 (+ 1 (p (- y 1)))))) (x (p 5)) (y x)) y) ⇒ 5
It must be 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. Another restriction is that the continuation of each ?init should not be invoked more than once.
Implementation responsibilities: Implementations must, during
the evaluation of an ?init expression, detect references to the
value of the corresponding ?variable or the ?variable of any
of the bindings that follow it in ?bindings. If an implementation
detects such a violation of the restriction, it must raise an exception
with condition type &assertion
. Implementations may or may not
detect that the continuation of each ?init is invoked more than
once. However, if the implementation detects this, it must raise an
exception with condition type &assertion
.
?mv-bindings must have the form:
((?formals1 ?init1) …)
where each ?init is an expression, and ?body is as described in baselib bodies. Any variable must not appear more than once in the set of ?formals.
The ?inits are evaluated in the current environment (in some
unspecified order), and the variables occurring in the ?formals
are bound to fresh locations containing the values returned by the
?inits, where the ?formals are matched to the return values
in the same way that the ?formals in a lambda
are matched
to the arguments in a procedure call. Then, the ?body is
evaluated in the extended environment, and the values of the last
expression of ?body are returned. Each binding of a variable has
?body as its region. If the ?formals do not match, an
exception with condition type &assertion
is raised.
(let-values (((a b) (values 1 2)) ((c d) (values 3 4))) (list a b c d)) ⇒ (1 2 3 4) (let-values (((a b . c) (values 1 2 3 4))) (list a b c)) ⇒ (1 2 (3 4)) (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 a b)
Notice the following special case:
(let-values ((all (values 1 2 3))) all) ⇒ (1 2 3)
which corresponds to the lambda
formals:
(define f (lambda all all)) (f 1 2 3) ⇒ (1 2 3)
?mv-bindings must have the form:
((?formals1 ?init1) …)
where each ?init is an expression, and ?body is as described in baselib bodies. In each ?formals, any variable must not appear more than once.
The let*-values
form is similar to let-values
, but the
?inits are evaluated and bindings created sequentially from left
to right, with the region including the bindings to its right as well as
?body. Thus the second ?init is evaluated in an environment
in which the bindings of the first ?formals 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)
NOTE While all of the variables bound by a
let-values
expression must be distinct, the variables bound by different ?formals of alet*-values
expression need not be distinct.
Next: baselib expressions sequencing, Previous: baselib expressions derived cond, Up: baselib expressions [Index]