For Development HEAD DRAFTSearch (procedure/syntax/module):

Next: , Previous: , Up: Core library   [Contents][Index]

6.16 Parameters and dynamic states

A parameter is Scheme’s way to implement dynamically scoped variables. It is codified in SRFI-39 and incorporated into R7RS.

It is a special procedure created by make-parameter. It accepts zero or one argument. When called without an argument, it returns the value in the current dynamic environment. If an argument is passed, it alters its value with the given value in the current dynamic environment, and returns the previous value.

Using parameterize macro, which is similar to let syntactially, rebinds the parameters’ value during execution of its body, dynamically rather than lexically.

(define var (make-parameter 0))

(define (show-var) (print (var)))

(show-var)  ; prints 0

(parameterize ((var 1))
  (show-var))    ; prints 1


(define f)

(parameterize ((var 2))
  (set! f (lambda () (show-var))))

(f) ; prints 0, since its out of the dynamic extent of var=2

A parameter’s value can be mutated by calling the parameter with the new value:

(define var (make-parameter 0))

(var) ; ⇒ 0

(var 1)

(var) ; ⇒ 1

;; Gauche extension: you can use set! too
(set! (var) 2)

(var) ; ⇒ 2

Originally, parameters in Scheme were simply a hack with an ordinary procedure and dynamic-wind to emulate dynamically scoped variables. The same mechanism have been used to manage dynamically scoped states, too.

As the experience accumulated, however, it is learned that it’s better to treat dynamically scoped variables and dynamically scoped states differently; efficient implementations differ, and they have slightly different semantics with delimited continuations. SRFI-226 incorporated this distinction.

As of Gauche 0.9.13, we adopt this distinction, too. See Difference of parameters and dynamic states, for the details.


6.16.1 Parameters

Function: make-parameter value :optional converter
Function: make-thread-parameter value :optional converter
Function: make-shared-parameter value :optional converter

[R7RS base][SRFI-226] Creates a parameter whose initial value is value. If an optional argument converter is given, it must be a procedure that takes one argument and returns one value; whenever the parameter’s value is about to change, the procedure is called with the given value, and the value the procedure returns will be the parameter’s value. The converter procedure can raise an error or reject to change the parameter’s value.

A parameter can be a thread parameter or a shared parameter. When you mutate a thread parameter, the change is only visible in the same thread; the value in other threads isn’t affected. On the other hand, the storage of a shared parameter is shared by all threads, and mutation is visible from all threads. However, once you parameterize it, mutation is only visible from the thread that shares the same parameterization.

R7RS only defines make-parameter and does not specify the behavior with threads. Up until 0.9.12, Gauche made the default parameter thread-local. However, SRFI-226 specifies the default parameter shared, and specify make-thread-parameter to be used to create a thread parameter.

For the backward compatibility, make-parameter still returns a thread parameter for the time being, unless you explicitly use srfi.226. Eventually we switch make-parameter to return a shared parameter, so you want to replace it with make-thread-parameter if that’s what you want. During transition, you can use make-shared-parameter (Gauche specific procedure) to explicitly create a shared parameter.

NB: In 0.9.9 and before, this procedure returns a parameter object, and we used object-apply method to make it behave like a procedure. However, R7RS explicitly defines the return values to be a procedure; notably, portable code expects (procedure? (make-parameter 'z)) returns #t.

As of 0.9.10, we switched make-parameter to return a procedure. It won’t change the external behavior, except when you test the parameter p with (is-a? p <parameter>); you have to use parameter? instead.

Macro: parameterize ((param value) …) body …

[R7RS base] Evaluates body …, with change parameter param’s value to the given value within the dynamic scope of body …. Returns the value(s) of the result of the last body.

If parameterize form is at a tail position and all params are parameter objects , body is also evaluated at a tail position. (This is required by SRFI-226, though not required by R7RS).

Note that R7RS and SRFI-226 requires param to be evaluated to a parameter. Gauche’s parameterize has been acceping dynamic states as well, but such usage is deprecated; you should use temporarily instead (see Dynamic states). In fact, Gauche checks if every param yields a parameter, at runtime, and if not, it switches to the legacy implementation which does not evaluate body at a tail position.

Some examples:

(define a (make-parameter 1))
(a) ⇒ 1
(a 2) ⇒ 1
(a) ⇒ 2
(parameterize ((a 3))
  (a)) ⇒ 3
(a) ⇒ 2
Function: parameter? obj

Returns #t iff obj is an object created by make-parameter.


6.16.2 Dynamic states

A dynamic state is a state that is kept during a certain dynamic extent of the code execution. It can be managed with a procedure that follows this protocol:

You can use temporarily macro in place of parameterize to change the state dynamically.

(define state
  (let val 0
    (case-lambda
      [() val]
      [(newval) (set! val newval)])))

(define (get-state) (state))

(get-state) ⇒ 0

(temporarily ([state 1])
  (get-state)) ⇒ 1

If you just manage a value, it is not much different from a parameter (without a converter) and parameterize. However, unlike parameterize, it is guaranteed that state is reset by calling the dynamic state with the previous value, when the control goes out of the dynamic scope. You can do more than just changing the internal values inside the procedure, such as switching state of external resource.

Macro: temporarily ((proc value) …) body …

Evaluates procs and values. Each proc must yield a dynamic state, i.e. a procedure that takes zero or one arguments.

Then the current state each proc represents is changed to value during evaluating body …. The state is restored when the control leaves body …. The results of the last expression of body will be returned.

Whenver control trasfers out of body, or reenters to body, the state of each proc is saved and restored.


6.16.3 Difference of parameters and dynamic states


Next: , Previous: , Up: Core library   [Contents][Index]


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT