From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Kevin Ryde Newsgroups: gmane.lisp.guile.devel Subject: doc srfi-39 parameters Date: Wed, 12 Jan 2005 11:11:54 +1100 Message-ID: <87k6qjsdyt.fsf@zip.com.au> NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1105489002 8318 80.91.229.6 (12 Jan 2005 00:16:42 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Wed, 12 Jan 2005 00:16:42 +0000 (UTC) Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Wed Jan 12 01:16:27 2005 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1CoWBW-0007Ia-00 for ; Wed, 12 Jan 2005 01:16:26 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1CoWN5-0004Fi-GL for guile-devel@m.gmane.org; Tue, 11 Jan 2005 19:28:23 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1CoWMS-0003vr-3v for guile-devel@gnu.org; Tue, 11 Jan 2005 19:27:44 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1CoWMP-0003uc-Md for guile-devel@gnu.org; Tue, 11 Jan 2005 19:27:42 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1CoWMP-0003tn-Ec for guile-devel@gnu.org; Tue, 11 Jan 2005 19:27:41 -0500 Original-Received: from [61.8.0.84] (helo=mailout1.pacific.net.au) by monty-python.gnu.org with esmtp (Exim 4.34) id 1CoW7R-0006m3-UL for guile-devel@gnu.org; Tue, 11 Jan 2005 19:12:14 -0500 Original-Received: from mailproxy2.pacific.net.au (mailproxy2.pacific.net.au [61.8.0.87]) by mailout1.pacific.net.au (8.12.3/8.12.3/Debian-7.1) with ESMTP id j0C0CAA6010051 for ; Wed, 12 Jan 2005 11:12:10 +1100 Original-Received: from localhost (ppp22A6.dyn.pacific.net.au [61.8.34.166]) by mailproxy2.pacific.net.au (8.12.3/8.12.3/Debian-7.1) with ESMTP id j0C0C8xG011293 for ; Wed, 12 Jan 2005 11:12:09 +1100 Original-Received: from gg by localhost with local (Exim 3.36 #1 (Debian)) id 1CoW79-0001HZ-00; Wed, 12 Jan 2005 11:11:55 +1100 Original-To: guile-devel@gnu.org Mail-Copies-To: never User-Agent: Gnus/5.110003 (No Gnus v0.3) Emacs/21.3 (gnu/linux) X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: main.gmane.org gmane.lisp.guile.devel:4650 X-Report-Spam: http://spam.gmane.org/gmane.lisp.guile.devel:4650 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 guess.) 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 example, (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 parameter. 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: ")) (get-input) ...) -- 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. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel