|
The three binding constructs
let,
let*, and
letrec give Scheme a block structure. The syntax of the three 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 variables become bound. In a
let* expression, the bindings and evaluations are performed sequentially. In a
letrec expression, all the bindings are in effect while their initial values are being computed, allowing mutually recursive definitions.
|
|
|
(let <bindings> <body>)
|
|
Where
<bindings> has the form
((<variable1> <init1>) . . .). Where each
<init> is an expression, and
<body> is a sequence of one or more expressions. A
<variable> cannot appear more than once in the list of variables being bound.
|
|
(let ((x 3)
|
|
|
(* x 3))
|
|
;; 9
|
|
|
Example 1-9.
|
|
|
The
<init>s are evaluated in the current environment, the
<variable>s are bound to fresh locations holding the results, the
<body> is evaluated in the extended environment, and the value of the last expression of
<body> returns. Each binding of a
<variable> has
<body> as its region.
|
|
(let* <bindings> <body>)
|
|
Where
<bindings> has the form
((<variable1> <init1>) . . .) and
<body> is a sequence of one or more expressions.
|
|
(let* ((x 3))
|
|
|
(define y (* x 3))
|
|
|
(define z (+ y 3))
|
|
|
(+ y z)
|
|
)
|
|
;; 21
|
|
|
Example 1-10.
|
|
|
let* is similar to
let, but the bindings are performed sequentially from left to right, and the region of a binding indicated by(<variable1> <init1>) is that part of the 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.
|
|
(letrec <bindings> <body>)
|
|
Where
<bindings> has the form
((<variable1> <init1>) . . .) and
<body> is a sequence of one or more expressions. It is an error for a
<variable> to appear more than once in the list of variables being bound.
|
|
(letrec ((x 12) (y 3)) (* x y))
|
|
;; 36
|
|
|
Example 1-11.
|
|
|
The
<variable>s are bound to fresh locations holding undefined values, the
<init>s are evaluated in the resulting environment, each
<variable> is assigned to the result of the corresponding
<init>, the
<body> is evaluated in the resulting environment, and value of the last expression in
<body> returns. Each binding of a
<variable> has the entire
letrec expression as its region, making it possible to define mutually recursive procedures.
|
|
|
One restriction on
letrec is very important--it must be possible to evaluate each
<init> without assigning or referring to the value of any
<variable>.
|