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 ((patterninit) ...) body
Declare new local variables as found in the
patterns. Eachpatternis matched against the correspondinginit. Theinits are evaluated in the current environment (in left-to-right onder), thevariables in thepatternss are bound to fresh locations holding the matched 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.(let ((x 2) (y 3)) (* x y)) ⇒ 6(let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x))) ⇒ 35An example with a non-trivial pattern:
(let (([a::double b::integer] (vector 4 5))) (cons b a)) ⇒ (5 . 4.0)
Syntax: let* ((patterninit) ...) body
The
let*binding construct is similar tolet, but the bindings are performed sequentially from left to right, and the region of avariables in apatternis that part of thelet*expression to the right of thepattern. 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
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