Next: Boxes, Previous: Procedures and continuations, Up: Core library [Contents][Index]
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.
• Parameters: | ||
• Dynamic states: | ||
• Difference of parameters and dynamic states: |
Next: Dynamic states, Previous: Parameters and dynamic states, Up: Parameters and dynamic states [Contents][Index]
[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.
[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
Returns #t
iff obj is an object created by
make-parameter
.
Next: Difference of parameters and dynamic states, Previous: Parameters, Up: Parameters and dynamic states [Contents][Index]
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.
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.
Previous: Dynamic states, Up: Parameters and dynamic states [Contents][Index]
Next: Boxes, Previous: Procedures and continuations, Up: Core library [Contents][Index]