Note that both parameter and value are expressions. It is an error if the value of any parameter expression is not a parameter object.
parameterize expression is used to change the values of
specified parameter objects during the evaluation of the body
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.
parameterize special form is standardized by SRFI 39 and
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
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.
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.
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
fluid-let temporarily rebinds existing variables. Unlike
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.