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 [:: ] typeinit) ...) body
Declare new local variables with the given
name, initial valueinit, and optional type specificationtype. Theinits are evaluated in the current environment (in left-to-right onder), thevariables are bound to fresh locations holding the results, thebodyis evaluated in the extended environment, and the values of the last expression of body are returned. Each binding of a variable hasbodyas its region. Iftypeis specified, then after the expressioninitis evaluated, the result coerced totype, and then assigned to the variable. Iftypeis 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 [:: ] typeinit) ...) body
The
let*binding construct is similar tolet, but the bindings are performed sequentially from left to right, and the region of avariableis 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. Thevariables need not be distinct.(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ⇒ 70
Syntax: letrec ((variable [:: ] typeinit) ...) body
Syntax: letrec* ((variable [:: ] typeinit) ...) body
The
variables are bound to fresh locations, eachvariableis assigned in left-to-right order to the result of the correspondinginit, thebodyis 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 avariablehas the entireletrecorletrec*expression as its region, making it possible to define mutually recursive procedures.In Kawa
letrecis defined as the same asletrec*. In standard Scheme the order of evaluation of theinits is undefined, as is the order of assignments. If the order matters, you should useletrec*.If it is not possible to evaluate each
initwithout assigning or referring to the value of the correspondingvariableor 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