Next: iklib gensym, Previous: iklib modules, Up: iklib [Index]
Parameters in Vicare are intended for customizing the behavior of a procedure during the dynamic execution of some piece of code. Parameters are first class entities (represented as procedures) that hold the parameter value. We can think of a parameter function as:
(let ((the-value ?init-value) (guard ?guard-func)) (case-lambda (() the-value) ((new-value) (set! the-value (guard new-value))) ((new-value guard?) (if guard? (set! the-value (guard new-value)) (set! the-value new-value)))))
where ?init-value is the parameter’s initialisation value and ?guard-func is a function accepting one argument and returning one value. The behaviour is as follows:
Parameter functions are created by make-parameter
; the
parameter’s initialisation value is not automatically passed
through the guard function by make-parameter
. About guarding or
not the initialisation value there are pros and cons for both the
choices; Vicare does not guard the initialisation value because
a parameter can be used to hold “complex” objects and it is not always
desirable to create one of those at program start time. When needed it
is possible to validate the value by explicitly writing the required
predicate.
As example, consider a parameter used to hold the “current database connection”; we may not want to connect to a database right at program start time. With a validating parameter: we should create a “null” connection object for the only purpose of initialising the parameter and then test for it; with a non–validating parameter: we just initialise the parameter to
#f
.
Parameters replace the older concept of using starred *global*
customization variables. For example, instead of writing:
(define *screen-width* 72)
and then mutating the variable *screen-width*
with set!
,
we could wrap the variable *screen-width*
with a
screen-width
parameter as follows:
(define *screen-width* 72) (define screen-width (case-lambda (() *screen-width*) ((x) (set! *screen-width* x))))
the value of screen-width
can now be passed as argument, returned
as a value, and exported from libraries. With parameters we can write
this code succinctly as:
(define screen-width (make-parameter 72))
Typical uses of the guard function include checking some constraints on
the passed argument or converting it to a different data type. The
screen-width
parameter may be constructed more robustly as:
(define screen-width (make-parameter 72 (lambda (w) (assert (and (integer? w) (exact? w))) (max w 1))))
this definition ensures, through assert
, that the argument passed
is an exact integer; it also ensures, through max
that the
assigned value is always positive.
Build and return a new parameter function using init as initialisation value and guard as guard function.
Parameters can be assigned to by simply calling the parameter procedure
with a single argument. The parameterize
syntax is used to set
the value of a parameter within the dynamic extent of the body
body* ...
expressions.
The lhs* ...
are expressions, each of which must evaluate to a
parameter. Such parameters are not necessarily constructed by
make-parameter
—any procedure that follows the parameters
protocol works.
The advantage of using parameterize
over explicitly assigning to
parameters (same argument applies to global variables) is that you’re
guaranteed that whenever control exits the body of a parameterize
expression, the value of the parameter is reset back to what it was
before the body expressions were entered. This is true even in the
presence of call/cc
, errors, and exceptions.
The following example shows how to set the text property of a terminal
window. The parameter terminal-property
sends an ANSI escape
sequence to the terminal whenever the parameter value is changed. The
use of terminal-property
within parameterize
changes the
property before (display "RED!")
is called and resets it back to
normal when the body returns.
(define terminal-property (make-parameter "0" (lambda (x) (display "\x1b;[") (display x) (display "m") x))) (display "Normal and ") (parameterize ((terminal-property "41;37")) (display "RED!")) (newline)
Notice that this syntax applies the parameters’ guard functions when setting new values, but does not apply them when restoring the original value.
Next: iklib gensym, Previous: iklib modules, Up: iklib [Index]