[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

doc srfi-39 parameters

From: Kevin Ryde
Subject: doc srfi-39 parameters
Date: Wed, 12 Jan 2005 11:11:54 +1100
User-agent: Gnus/5.110003 (No Gnus v0.3) Emacs/21.3 (gnu/linux)

Some words below about srfi-39 parameters.  I think the basic usage is
pretty straightforward, so I've tried to get that in first.

Experts on threading should check the paras at the end to see they're
what is supposed to happen.  (It's all just fluids in disguise I

2.2 SRFI-39 - Parameters

This SRFI defines parameter objects, which implement dynamically bound
locations for values.  The functions below are available from

     (use-modules (srfi srfi-39))

   A parameter object is a procedure.  Called with no arguments it
returns its value, called with one argument it sets the value.

     (define my-param (make-parameter 123))
     (my-param) => 123
     (my-param 456)
     (my-param) => 456

   The `parameterize' special form establishes new locations for
parameters, those having effect within the dynamic scope of the
`parameterize' body.  Leaving that body restores the previous
locations, or re-entering through a saved continuation will again use
the new locations.

     (parameterize ((my-param 789))
       (my-param) => 789
     (my-param) => 456

   Parameters are like dynamically bound variables in other Lisp
dialets.  They allow an application to establish parameter settings (as
the name suggests) just for the execution of a particular bit of code,
restoring when done.  Examples of such parameters might be
case-sensitivity for a search, or a prompt for user input.

   Global variables are not as good as parameter objects for this sort
of thing.  Changes to them are visible to all threads, but in Guile
parameter object locations are per-thread, thereby truely limiting the
effect of `parameterize' to just its dynamic execution.

   Passing arguments to functions is thread-safe, but arguments soon
become tedious when there's more than a few or when they need to pass
down through several layers of calls before reaching the point they
should affect.  And introducing a new setting to existing code is often
easier with a parameter object than adding arguments.

 -- Function: make-parameter init [converter]
     Return a new parameter object, with initial value INIT.

     A parameter object is a procedure.  When called `(param)' it
     returns its value, or a call `(param val)' sets its value.  For

          (define my-param (make-parameter 123))
          (my-param) => 123

          (my-param 456)
          (my-param) => 456

     If a CONVERTER is given, then a call `(CONVERTER val)' is made for
     each value set, its return is the value stored.  Such a call is
     made for the INIT initial value too.

     A CONVERTER allows values to be validated, or put into a canonical
     form.  For example,

          (define my-param (make-parameter 123
                             (lambda (val)
                               (if (not (number? val))
                                   (error "must be a number"))
                               (inexact->exact val))))
          (my-param 0.75)
          (my-param) => 3/4

 -- library syntax: parameterize ((param value) ...) body ...
     Establish a new dynamic scope with the given PARAMs bound to new
     locations and set to the given VALUEs.  BODY is evaluated in that
     environment, the result is the return from the last form in BODY.

     Each PARAM is an expression which is evaluated to get the
     parameter object.  Often this will just be the name of a variable
     holding the object, but it can be anything that evaluates to a

     The PARAM expressions and VALUE expressions are all evaluated
     before establishing the new dynamic bindings, and they're
     evaluated in an unspecified order.

     For example,

          (define prompt (make-parameter "Type something: "))
          (define (get-input)
            (display (prompt))

          (parameterize ((prompt "Type a number: "))

 -- Parameter object: current-input-port [new-port]
 -- Parameter object: current-output-port [new-port]
 -- Parameter object: current-error-port [new-port]
     This SRFI extends these core `current-input-port' and
     `current-output-port', making them parameter objects.  The
     Guile-specific `current-error-port' is extended too, for
     consistency.  (*note Default Ports::.)

     This is an upwardly compatible extension, a plain call like
     `(current-input-port)' still returns the current input port, and
     `set-current-input-port' can still be used.  But the port can now
     also be set with `(current-input-port my-port)' and bound
     dynamically with `parameterize'.

 -- Function: with-parameters* param-list value-list thunk
     Establish a new dynamic scope, as per `parameterize' above, taking
     parameters from PARAM-LIST and corresponding values from
     VALUES-LIST.  A call `(THUNK)' is made in the new scope and the
     result from that THUNK is the return from `with-parameters*'.

     This function is a Guile-specific addition to the SRFI, it's
     similar to the core `with-fluids*' (*note Fluids::).

   As alluded to above, in Guile each thread is a separate dynamic root
for execution, and the locations behind parameters are private to each
thread.  This includes the initial location for a parameter (ie.
outside any `parameterize').  When a parameter is created it
effectively has a separate initial location in each thread, all
initialized to the given INIT value.

   When a new thread is created, the values of the parameters in the
originating thread are inherited in the new thread, but with new
locations in that new thread (so changes there don't affect the
originating thread).

   SRFI-39 doesn't specify the interaction between parameter objects and
threads, so the threading behaviour described here should be regarded
as Guile-specific.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]