4.3. Local Binding


4.3. Local Binding

(let ((var val) ...) exp1 exp2 ...)

syntax

returns: the value of the final expression

let establishes local variable bindings. Each variable var is bound to the value of the corresponding expression val. The body of the let, in which the variables are bound, is the sequence of expressions exp1 exp2 .

The forms let, let*, and letrec (let* and letrec are described after let) are similar but serve slightly different purposes. With let, in contrast with let* and letrec, the expressions val are all outside the scope of the variables var . Also, in contrast with let*, no ordering is implied for the evaluation of the expressions val . They may be evaluated from left to right, from right to left, or in any other order at the discretion of the implementation. Use let whenever the values are independent of the variables and the order of evaluation is unimportant.

The body of a let expression may begin with a sequence of definitions, which establish bindings local to the body of the let. See Section 3.5 or Section 4.4.

The following definition of let shows the typical derivation of let from lambda.

 (define-syntax let   (syntax-rules ()     (( ((x v) ...) e1 e2 ...)      ((lambda (x ...) e1 e2 ...) v ...)))) (let ((x (* 3.0 3.0)) (y (* 4.0 4.0)))   (sqrt (+ x y)))  5.0 (let ((x 'a) (y '(b c)))   (cons x y))  (a b c) (let ((x 0) (y 1))   (let ((x y) (y x))     (list x y)))  (1 0) 

Another form of let, named let, is described in Section 5.4, and a definition of the full let can be found on page 201.

(let* ((var val) ...) exp1 exp2 ...)

syntax

returns: the value of the final expression

let* is similar to let except that the expressions val are evaluated in sequence from left to right, and each of these expressions is within the scope of the variables to the left. Use let* when there is a linear dependency among the values or when the order of evaluation is important.

Any let* expression may be converted to a set of nested let expressions. The following definition of let* demonstrates the typical transformation.

 (define-syntax let*   (syntax-rules ()     (( () e1 e2 ...)      (let () e1 e2 ...))     (( ((x1 v1) (x2 v2) ...) e1 e2 ...)      (let ((x1 v1))        (let* ((x2 v2) ...) e1 e2 ...))))) (let* ((x (* 5.0 5.0))        (y (- x (* 4.0 4.0))))   (sqrt y))  3.0 (let ((x 0) (y 1))   (let* ((x y) (y x))     (list x y)))  (1 1) 

(letrec ((var val) ...) exp1 exp2 ...)

syntax

returns: the value of the final expression

letrec is similar to let and let*, except that all of the expressions val are within the scope of all of the variables var . letrec allows the definition of mutually recursive procedures.

The order of evaluation of the expressions val is unspecified, so it is an error to reference any of the variables bound by the letrec expression before all of the values have been computed. (Occurrence of a variable within a lambda expression does not count as a reference, unless the resulting procedure is applied before all of the values have been computed.)

Choose letrec over let or let* when there is a circular dependency among the variables and their values and when the order of evaluation is unimportant.

A letrec expression of the form

 (letrec ((var val) ...) body) 

may be expressed in terms of let and set! as

 (let ((var #f) ...)   (let ((temp val) ...)     (set! var temp) ...     (let () body))) 

where temp are unique variables, one for each (var val) pair. The outer let expression establishes the variable bindings. The initial value given each variable is unimportant, so any value suffices in place of #f. The bindings are established first so that the values may contain occurrences of the variables, i.e., so that the values are computed within the scope of the variables. The middle let evaluates the values and binds them to the temporary variables, and the set! expressions assign each variable to the corresponding value. The inner let is present in case body contains internal definitions.

This transformation does not enforce the restriction that the values must not directly reference one of the variables. More elaborate transformations that enforce this restriction and produce more efficient code are possible [23].

A definition of letrec performing this transformation is shown on page 199.

 (letrec ((sum (lambda (x)                 (if (zero? x)                     0                     (+ x (sum (- x 1))))))) (sum 5))  15 




The Scheme Programming Language
The Scheme Programming Language
ISBN: 026251298X
EAN: 2147483647
Year: 2003
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net