diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index 3908455e8..0209535cf 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -37,6 +37,7 @@ get the relevant SRFI documents from the SRFI home page * SRFI-19:: Time/Date library. * SRFI-26:: Specializing parameters * SRFI-31:: A special form `rec' for recursive evaluation +* SRFI-39:: Parameter objects @end menu @@ -2060,6 +2061,169 @@ The second syntax can be used to create anonymous recursive functions: guile> @end lisp + +@node SRFI-39 +@subsection SRFI-39 - Parameters +@cindex SRFI-39 +@cindex parameter object +@tindex Parameter + +This SRFI provides parameter objects, which implement dynamically +bound locations for values. The functions below are available from + +@example +(use-modules (srfi srfi-39)) +@end example + +A parameter object is a procedure. Called with no arguments it +returns its value, called with one argument it sets the value. + +@example +(define my-param (make-parameter 123)) +(my-param) @result{} 123 +(my-param 456) +(my-param) @result{} 456 +@end example + +The @code{parameterize} special form establishes new locations for +parameters, those new locations having effect within the dynamic scope +of the @code{parameterize} body. Leaving restores the previous +locations, or re-entering through a saved continuation will again use +the new locations. + +@example +(parameterize ((my-param 789)) + (my-param) @result{} 789 + ) +(my-param) @result{} 456 +@end example + +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 @code{parameterize} to just its dynamic execution. + +Passing arguments to functions is thread-safe, but that soon becomes +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. + + +@sp 1 +@defun make-parameter init [converter] +Return a new parameter object, with initial value @var{init}. + +A parameter object is a procedure. When called @code{(param)} it +returns its value, or a call @code{(param val)} sets its value. For +example, + +@example +(define my-param (make-parameter 123)) +(my-param) @result{} 123 + +(my-param 456) +(my-param) @result{} 456 +@end example + +If a @var{converter} is given, then a call @code{(@var{converter} +val)} is made for each value set, its return is the value stored. +Such a call is made for the @var{init} initial value too. + +A @var{converter} allows values to be validated, or put into a +canonical form. For example, + +@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) @result{} 3/4 +@end example +@end defun + +@deffn {library syntax} parameterize ((param value) @dots{}) body @dots{} +Establish a new dynamic scope with the given @var{param}s bound to new +locations and set to the given @var{value}s. @var{body} is evaluated +in that environment, the result is the return from the last form in +@var{body}. + +Each @var{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 @var{param} expressions and @var{value} expressions are all +evaluated before establishing the new dynamic bindings, and they're +evaluated in an unspecified order. + +For example, + +@example +(define prompt (make-parameter "Type something: ")) +(define (get-input) + (display (prompt)) + ...) + +(parameterize ((prompt "Type a number: ")) + (get-input) + ...) +@end example +@end deffn + +@deffn {Parameter object} current-input-port [new-port] +@deffnx {Parameter object} current-output-port [new-port] +@deffnx {Parameter object} current-error-port [new-port] +This SRFI extends the core @code{current-input-port} and +@code{current-output-port}, making them parameter objects. The +Guile-specific @code{current-error-port} is extended too, for +consistency. (@pxref{Default Ports}.) + +This is an upwardly compatible extension, a plain call like +@code{(current-input-port)} still returns the current input port, and +@code{set-current-input-port} can still be used. But the port can now +also be set with @code{(current-input-port my-port)} and bound +dynamically with @code{parameterize}. +@end deffn + +@defun with-parameters* param-list value-list thunk +Establish a new dynamic scope, as per @code{parameterize} above, +taking parameters from @var{param-list} and corresponding values from +@var{values-list}. A call @code{(@var{thunk})} is made in the new +scope and the result from that @var{thunk} is the return from +@code{with-parameters*}. + +This function is a Guile-specific addition to the SRFI, it's similar +to the core @code{with-fluids*} (@pxref{Fluids}). +@end defun + + +@sp 1 +Parameter objects are implemented using fluids (@pxref{Fluids}), so +each dynamic root has it's own parameter locations. That includes the +separate locations when outside any @code{parameterize} form. When a +parameter is created it gets a separate initial location in each +dynamic root, all initialized to the given @var{init} value. + +As alluded to above, because each thread is a separate dynamic root, +each thread has it's own locations behind parameter objects, and +changes in one thread are not visible to any other. When a new +dynamic root or thread is created, the values of parameters in the +originating context are copied, into new locations. + +SRFI-39 doesn't specify the interaction between parameter objects and +threads, so the threading behaviour described here should be regarded +as Guile-specific. + + @c srfi-modules.texi ends here @c Local Variables: