Next: ASCII character encoding, Previous: Filenames, Up: System features
The fluids
structure provides a facility for dynamically bound
resources, like special variables in Common Lisp, but with first-class,
unforgeable objects.
Every thread in Scheme48 maintains a
fluid or dynamic environment. It maps fluid descriptors to
their values, much like a lexical environment maps names to their
values. The dynamic environment is implemented by deep binding and
dynamically scoped. Fluid variables are represented as first-class
objects for which there is a top-level value and possibly a binding in
the current dynamic environment. Escape procedures, as created with
Scheme's call-with-current-continuation
, also store & preserve
the dynamic environment at the time of their continuation's capture and
restore it when invoked.
The convention for naming variables that are bound to fluid objects
is to add a prefix of $
(dollar sign); e.g., $foo
.
Fluid
returns the value that the current dynamic environment associates with fl, if it has an association; if not, it returns fl's top-level value, as passed tomake-fluid
to create fl.Set-fluid!
assigns the value of the association in the current dynamic environment for fl to value, or, if there is no such association, it assigns the top-level value of fl to value. Direct assignment of fluids is deprecated, however, and may be removed in a later release; instead, programmers should use fluids that are bound to mutable cells.Fluid-cell-ref
andfluid-cell-set!
are conveniences for this; they simply call the corresponding cell operations after fetching the cell that the fluid refers to by usingfluid
.
These dynamically bind their fluid arguments to the corresponding value arguments and apply thunk with the new dynamic environment, restoring the old one after thunk returns and returning the value it returns.
(define $mumble (make-fluid 0)) (let ((a (fluid $mumble)) (b (let-fluid $mumble 1 (lambda () (fluid $mumble)))) (c (fluid $mumble)) (d (let-fluid $mumble 2 (lambda () (let-fluid $mumble 3 (lambda () (fluid $mumble))))))) (list a b c d)) => (0 1 0 3) (let ((note (lambda (when) (display when) (display ": ") (write (fluid $mumble)) (newline)))) (note 'initial) (let-fluid $mumble 1 (lambda () (note 'let-fluid))) (note 'after-let-fluid) (let-fluid $mumble 1 (lambda () (note 'outer-let-fluid) (let-fluid $mumble 2 (lambda () (note 'inner-let-fluid))))) (note 'after-inner-let-fluid) ((call-with-current-continuation (lambda (k) (lambda () (let-fluid $mumble 1 (lambda () (note 'let-fluid-within-cont) (let-fluid $mumble 2 (lambda () (note 'inner-let-fluid-within-cont))) (k (lambda () (note 'let-fluid-thrown))))))))) (note 'after-throw)) -| initial: 0 -| let-fluid: 1 -| after-let-fluid: 0 -| outer-let-fluid: 1 -| inner-let-fluid: 2 -| let-fluid-within-cont: 1 -| inner-let-fluid-within-cont: 2 -| let-fluid-thrown: 0 -| after-throw: 0