Next: , Previous: , Up: Special Forms   [Contents][Index]


2.3 Dynamic Binding

special form: parameterize ((parameter value) …) expression expression …

Note that both parameter and value are expressions. It is an error if the value of any parameter expression is not a parameter object.

A parameterize expression is used to change the values of specified parameter objects during the evaluation of the body expressions.

The parameter and value expressions are evaluated in an unspecified order. The body is evaluated in a dynamic environment in which each parameter is bound to the converted value—the result of passing value to the conversion procedure specified when the parameter was created. Then the previous value of parameter is restored without passing it to the conversion procedure. The value of the parameterize expression is the value of the last body expression.

The parameterize special form is standardized by SRFI 39 and by R7RS.

Parameter objects can be used to specify configurable settings for a computation without the need to pass the value to every procedure in the call chain explicitly.

(define radix
  (make-parameter
   10
   (lambda (x)
     (if (and (exact-integer?  x) (<= 2 x 16))
         x
         (error "invalid radix")))))

(define (f n) (number->string n (radix)))

(f 12)                                  ⇒ "12"
(parameterize ((radix 2))
  (f 12))                               ⇒ "1100"
(f 12)                                  ⇒ "12"
(radix 16)                              error→ Wrong number of arguments
(parameterize ((radix 0))
  (f 12))                               error→ invalid radix

A dynamic binding changes the value of a parameter (see Parameters) object temporarily, for a dynamic extent. The set of all dynamic bindings at a given time is called the dynamic environment. The new values are only accessible to the thread that constructed the dynamic environment, and any threads created within that environment.

The extent of a dynamic binding is defined to be the time period during which calling the parameter returns the new value. Normally this time period begins when the body is entered and ends when it is exited, a contiguous time period. However Scheme has first-class continuations by which it is possible to leave the body and reenter it many times. In this situation, the extent is non-contiguous.

When the body is exited by invoking a continuation, the current dynamic environment is unwound until it can be re-wound to the environment captured by the continuation. When the continuation returns, the process is reversed, restoring the original dynamic environment.

The following example shows the interaction between dynamic binding and continuations. Side effects to the binding that occur both inside and outside of the body are preserved, even if continuations are used to jump in and out of the body repeatedly.

(define (complicated-dynamic-parameter)
  (let ((variable (make-settable-parameter 1))
        (inside-continuation))
    (write-line (variable))
    (call-with-current-continuation
     (lambda (outside-continuation)
       (parameterize ((variable 2))
         (write-line (variable))
         (variable 3)
         (call-with-current-continuation
          (lambda (k)
            (set! inside-continuation k)
            (outside-continuation #t)))
         (write-line (variable))
         (set! inside-continuation #f))))
    (write-line (variable))
    (if inside-continuation
        (begin
          (variable 4)
          (inside-continuation #f)))))

Evaluating ‘(complicated-dynamic-binding)’ writes the following on the console:

1
2
1
3
4

Commentary: the first two values written are the initial binding of variable and its new binding inside parameterize’s body. Immediately after they are written, the binding visible in the body is set to ‘3’, and outside-continuation is invoked, exiting the body. At this point, ‘1’ is written, demonstrating that the original binding of variable is still visible outside the body. Then we set variable to ‘4’ and reenter the body by invoking inside-continuation. At this point, ‘3’ is written, indicating that the binding modified in the body is still the binding visible in the body. Finally, we exit the body normally, and write ‘4’, demonstrating that the binding modified outside of the body was also preserved.

2.3.1 Fluid-Let

The fluid-let special form can change the value of any variable for a dynamic extent, but it is difficult to implement in a multi-processing (SMP) world. It and the cell object type (see Cells) are now deprecated. They are still available and functional in a uni-processing (non-SMP) world, but will signal an error when used in an SMP world. The parameterize special form (see parameterize) should be used instead.

special form: fluid-let ((variable init) …) expression expression …

The inits are evaluated in the current environment (in some unspecified order), the current values of the variables are saved, the results are assigned to the variables, the expressions are evaluated sequentially in the current environment, the variables are restored to their original values, and the value of the last expression is returned.

The syntax of this special form is similar to that of let, but fluid-let temporarily rebinds existing variables. Unlike let, fluid-let creates no new bindings; instead it assigns the value of each init to the binding (determined by the rules of lexical scoping) of its corresponding variable.

MIT/GNU Scheme allows any of the inits to be omitted, in which case the corresponding variables are temporarily unassigned.

An error of type condition-type:unbound-variable is signalled if any of the variables are unbound. However, because fluid-let operates by means of side effects, it is valid for any variable to be unassigned when the form is entered.


Next: , Previous: , Up: Special Forms   [Contents][Index]