Next: , Previous: , Up: iklib   [Index]


6.37 Parameters

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.

Procedure: make-parameter init
Procedure: make-parameter init guard

Build and return a new parameter function using init as initialisation value and guard as guard function.

Syntax: parametrise ((?lhs ?rhs) …) ?body0 ?body
Syntax: parameterize ((?lhs ?rhs) …) ?body0 ?body
Syntax: parameterise ((?lhs ?rhs) …) ?body0 ?body

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: , Previous: , Up: iklib   [Index]