The binding constructs
letrec* give Scheme a block structure, like Algol 60.
The syntax of these 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
expressions, all the bindings are in effect while their initial
values are being computed, thus allowing mutually recursive definitions.
Declare new local variables as found in the patterns. Each pattern is matched against the corresponding init. The inits are evaluated in the current environment (in left-to-right onder), the variables in the patternss are bound to fresh locations holding the matched 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
An example with a non-trivial pattern:
(let (([a::double b::integer] (vector 4 5))) (cons b a)) ⇒ (5 . 4.0)
let* binding construct is similar to
but the bindings are performed sequentially from left to
right, and the region of a variables in a pattern
is that part of the
let* expression to the right of
the pattern. Thus the second pattern is matched in an environment
in which the bindings from the first pattern are visible, and so on.
(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ⇒ 70
The variables are bound to fresh locations,
each variable is assigned in left-to-right order
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.
Despite the left-to-right evaluation and assignment order, each binding of a
variable has the entire
expression as its region,
making it possible to define mutually recursive procedures.
letrec is defined as the same as
In standard Scheme the order of evaluation of the inits
is undefined, as is the order of assignments.
If the order matters, you should use
If it is not possible to evaluate each init without assigning or referring to the value of the corresponding variable or the variables that follow it, it is an error.
(letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88)) ⇒ #t