Next: Lazy evaluation, Previous: Definitions, Up: Program structure [Contents][Index]
The binding constructs let
, let*
, letrec
,
and 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 letrec
and letrec*
expressions, all the bindings are in effect while their initial
values are being computed, thus allowing mutually recursive definitions.
((
pattern init)
...)
body ¶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)
((
pattern init)
...)
body ¶The let*
binding construct is similar to let
,
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
((
variable [::
type] init)
...)
body ¶((
variable [::
type] init)
...)
body ¶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 letrec
or letrec*
expression as its region,
making it possible to define mutually recursive procedures.
In Kawa letrec
is defined as the same as letrec*
.
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 letrec*
.
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
Next: Lazy evaluation, Previous: Definitions, Up: Program structure [Contents][Index]