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.
Syntax: let
((
variable
[::
] type
init
)
...
)
body
Declare new local variables with the given
name
, initial valueinit
, and optional type specificationtype
. Theinit
s are evaluated in the current environment (in left-to-right onder), thevariable
s are bound to fresh locations holding the results, thebody
is evaluated in the extended environment, and the values of the last expression of body are returned. Each binding of a variable hasbody
as its region. Iftype
is specified, then after the expressioninit
is evaluated, the result coerced totype
, and then assigned to the variable. Iftype
is not specified, it defaults toObject
.(let ((x 2) (y 3)) (* x y)) ⇒ 6(let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x))) ⇒ 35
Syntax: let*
((
variable
[::
] type
init
)
...
)
body
The
let*
binding construct is similar tolet
, but the bindings are performed sequentially from left to right, and the region of avariable
is that part of thelet*
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. Thevariable
s need not be distinct.(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ⇒ 70
Syntax: letrec
((
variable
[::
] type
init
)
...
)
body
Syntax: letrec*
((
variable
[::
] type
init
)
...
)
body
The
variable
s are bound to fresh locations, eachvariable
is assigned in left-to-right order to the result of the correspondinginit
, thebody
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 avariable
has the entireletrec
orletrec*
expression as its region, making it possible to define mutually recursive procedures.In Kawa
letrec
is defined as the same asletrec*
. In standard Scheme the order of evaluation of theinit
s is undefined, as is the order of assignments. If the order matters, you should useletrec*
.If it is not possible to evaluate each
init
without assigning or referring to the value of the correspondingvariable
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