123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879 |
- @node System features
- @section System features
- Scheme48 provides a variety of miscellaneous features built-in to the
- system.
- @menu
- * Miscellaneous features::
- * Various utilities::
- * Filenames::
- * Fluid/dynamic bindings::
- * ASCII character encoding::
- * Integer enumerations::
- * Cells::
- * Queues::
- * Hash tables::
- * Weak references::
- * Type annotations::
- * Explicit renaming macros::
- @end menu
- @node Miscellaneous features
- @subsection Miscellaneous features
- @stindex features
- The structure @code{features} provides some very miscellaneous features
- in Scheme48.
- @cindex immutability
- @cindex mutability
- @deffn procedure immutable? object @returns{} boolean
- @deffnx procedure make-immutable! object @returns{} object
- All Scheme objects in Scheme48 have a flag determining whether or not
- they may be mutated. All immediate Scheme objects (@code{()},
- @code{#f}, @etc{}) are immutable; all fixnums (small integers) are
- immutable; and all stored objects --- vectors, pairs, @etc{} --- may be
- mutable. @code{Immutable?} returns @code{#t} if @var{object} may not
- be mutated, and @code{make-immutable!}, a bit ironically, modifies
- @var{object} so that it may not be mutated, if it was not already
- immutable, and returns it.
- @lisp
- (immutable? #t) @result{} #t
- (define p (cons 1 2))
- (immutable? p) @result{} #f
- (car p) @result{} 1
- (set-car! p 5)
- (car p) @result{} 5
- (define q (make-immutable! p))
- (eq? p q) @result{} #t
- (car p) @result{} 5
- (immutable? q) @result{} #t
- (set-car! p 6) @error{} immutable pair@end lisp
- @end deffn
- @deffn procedure string-hash string @returns{} integer-hash-code
- Computes a basic but fast hash of @var{string}.
- @lisp
- (string-hash "Hello, world!") @result{} 1161@end lisp
- @end deffn
- @cindex forcing buffered output
- @cindex output port buffer forcing
- @cindex buffered output forcing
- @cindex flushing output buffers
- @deffn procedure force-output port @returns{} unspecified
- Forces all buffered output to be sent out of @var{port}.
- This is identical to the binding of the same name exported by the
- @embedref{Ports, @code{i/o} structure}.
- @end deffn
- @cindex noise output
- @deffn procedure current-noise-port @returns{} output-port
- The current noise port is a port for sending noise messages that are
- inessential to the operation of a program.
- @end deffn
- @stindex silly
- The @code{silly} structure exports a single procedure, implemented as
- a VM primitive for the silly reason of efficiency, hence the name of
- the structure.@footnote{The author of this manual is not at fault for
- this nomenclature.} It is used in an inner loop of the reader.
- @deffn procedure reverse-list->string char-list count @returns{} string
- Returns a string of the first @var{count} characters in
- @var{char-list}, in reverse. It is a serious error if @var{char-list}
- is not a list whose length is at least @var{count}; the error is not
- detected by the VM, so bogus pointers may be involved as a result.
- Use this routine with care in inner loops.
- @end deffn
- @stindex debug-messages
- The @code{debug-messages} structure exports a procedure for emitting
- very basic debugging messages for low-level problems.
- @deffn procedure debug-message item @dots{} @returns{} unspecified
- Prints @var{item} @dots{} directly to an error port,@footnote{On Unix,
- this is @code{stderr}, the standard I/O error output file.}
- eliding buffering and thread synchronization on the Scheme side.
- Objects are printed as follows:
- @itemize
- @item Fixnums (small integers) are written in decimal.
- @item Characters are written literally with a @code{#\} prefix. No
- naming translation is performed, so the space and newline characters
- are written literally, not as @code{#\space} or @code{#\newline}.
- @item Records are written as #@{@var{type-name}@}, where
- @var{type-name} is the name of the record's type.
- @item Strings and symbols are written literally.
- @item Booleans and the empty list are written normally, @ie{} as
- @code{#t}, @code{#f}, or @code{()}.
- @item Pairs are written as @code{(...)}.
- @item Vectors are written as @code{#(...)}.
- @item Objects of certain primitive types are written as
- #@{@var{type}@}: procedures, templates, locations, code (byte)
- vectors, and continuations.@footnote{Continuations here are in the
- sense of VM stack frames, not escape procedures as obtained using
- @code{call-with-current-continuation}.}
- @item Everything else is printed as #@{???@}.
- @end itemize
- @end deffn
- @stindex code-quote
- The @code{code-quote} structure exports a variant of @code{quote} that
- is useful in some sophisticated macros.
- @deffn {special form} code-quote object @returns{} object
- Evaluates to the literal value of @var{object}. This is semantically
- identical to @code{quote}, but @var{object} may be anything, and the
- compiler will not signal any warnings regarding its value, while such
- warnings would be signalled for @code{quote} expressions that do not
- wrap readable S-expressions: arbitrary, compound, unreadable data may
- be stored in @code{code-quote}. Values computed at compile-time may
- thus be transmitted to run-time code. However, care should be taken
- in doing this.
- @end deffn
- @node Various utilities
- @subsection Various utilities
- @stindex util
- The @code{util} structure contains some miscellaneous utility routines
- extensively used internally in the run-time system. While they are not
- meant to compose a comprehensive library (such as, for example, [SRFI
- 1]), they were found useful in building the run-time system without
- introducing massive libraries into the core of the system.
- @cindex unspecific
- @cindex unspecified
- @deffn procedure unspecific @returns{} unspecific
- Returns Scheme48's @dfn{unspecific} token, which is used wherever R5RS
- uses the term `unspecific' or `unspecified.' In this manual, the term
- `unspecified' is used to mean that the values returned by a particular
- procedure are not specified and may be anything, including a varying
- number of values, whereas `unspecific' refers to Scheme48's specific
- `unspecific' value that the @code{unspecific} procedure returns.
- @end deffn
- @deffn procedure reduce kons knil list @returns{} final-knil
- Reduces @var{list} by repeatedly applying @var{kons} to elements of
- @var{list} and the current @var{knil} value. This is the fundamental
- list recursion operator.
- @lisp
- (reduce @var{kons} @var{knil}
- (cons @var{elt@sub{1}}
- (cons @var{elt@sub{2}}
- (@dots{}(cons @var{elt@sub{N}} '())@dots{}))))
- @equiv{}
- (@var{kons} @var{elt@sub{1}}
- (@var{kons} @var{elt@sub{2}}
- (@dots{}(@var{kons} @var{elt@sub{N}} @var{knil})@dots{})))@end lisp
- Example:
- @lisp
- (reduce append '() '((1 2 3) (4 5 6) (7 8 9)))
- @result{} (1 2 3 4 5 6 7 8 9)
- (append '(1 2 3)
- (append '(4 5 6)
- (append '(7 8 9) '())))
- @result{} (1 2 3 4 5 6 7 8 9)@end lisp
- @end deffn
- @deffn procedure fold combiner list accumulator @returns{} final-accumulator
- Folds @var{list} into an accumulator by repeatedly combining each
- element into an accumulator with @var{combiner}. This is the
- fundamental list iteration operator.
- @lisp
- (fold @var{combiner}
- (list @var{elt@sub{1}} @var{elt@sub{2}} @dots{} @var{elt@sub{N}})
- @var{accumulator})
- @equiv{}
- (let* ((accum@sub{1} (@var{combiner} @var{elt@sub{1}} @var{accumulator}))
- (accum@sub{2} (@var{combiner} @var{elt@sub{2}} accum@sub{1}))
- @dots{}
- (accum@sub{N} (@var{combiner} @var{elt@sub{N}} accum@sub{N-1})))
- accum@sub{N})@end lisp
- Example:
- @lisp
- (fold cons '() '(a b c d))
- @result{} (d c b a)
- (cons 'd (cons 'c (cons 'b (cons 'a '()))))
- @result{} (d c b a)@end lisp
- @end deffn
- @deffn procedure fold->2 combiner list accumulator@sub{1} accumulator@sub{2} @returns{} [final-accumulator@sub{1} final-accumulator@sub{2}]
- @deffnx procedure fold->3 combiner list accumulator@sub{1} accumulator@sub{2} accumulator@sub{3} @returns{} [final-accumulator@sub{1} final-accumulator@sub{2} final-accumulator@sub{3}]
- Variants of @code{fold} for two and three accumulators, respectively.
- @lisp
- ;;; Partition @var{list} by elements that satisfy @var{pred?} and those
- ;;; that do not.
- (fold->2 (lambda (elt satisfied unsatisfied)
- (if (@var{pred?} elt)
- (values (cons elt satisfied) unsatisfied)
- (values satisfied (cons elt unsatisfied))))
- @var{list}
- '() '())@end lisp
- @end deffn
- @deffn procedure filter predicate list @returns{} filtered-list
- Returns a list of all elements in @var{list} that satisfy
- @var{predicate}.
- @lisp
- (filter odd? '(3 1 4 1 5 9 2 6 5 3 5))
- @result{} (3 1 1 5 9 5 3 5)@end lisp
- @end deffn
- @deffn procedure posq object list @returns{} integer or @code{#f}
- @deffnx procedure posv object list @returns{} integer or @code{#f}
- @deffnx procedure position object list @returns{} integer or @code{#f}
- These find the position of the first element equal to @var{object} in
- @var{list}. @code{Posq} compares elements by @code{eq?}; @code{posv}
- compares by @code{eqv?}; @code{position} compares by @code{equal?}.
- @lisp
- (posq 'c '(a b c d e f))
- @result{} 2
- (posv 1/2 '(1 1/2 2 3/2))
- @result{} 1
- (position '(d . e) '((a . b) (b . c) (c . d) (d . e) (e . f)))
- @result{} 3@end lisp
- @end deffn
- @deffn procedure any predicate list @returns{} value or @code{#f}
- @deffnx procedure every predicate list @returns{} boolean
- @code{Any} returns the value that @var{predicate} returns for the first
- element in @var{list} for which @var{predicate} returns a true value;
- if no element of @var{list} satisfied @var{predicate}, @code{any}
- returns @code{#f}. @code{Every} returns @code{#t} if every element of
- @var{list} satisfies @var{predicate}, or @code{#f} if there exist any
- that do not.
- @lisp
- (any (lambda (x) (and (even? x) (sqrt x)))
- '(0 1 4 9 16))
- @result{} 2
- (every odd? '(1 3 5 7 9))
- @result{} #t@end lisp
- @end deffn
- @deffn procedure sublist list start end @returns{} list
- Returns a list of the elements in @var{list} including & after that at
- the index @var{start} and before the index @var{end}.
- @lisp
- (sublist '(a b c d e f g h i) 3 6) @result{} (d e f)@end lisp
- @end deffn
- @deffn procedure last list @returns{} value
- Returns the last element in @var{list}. @code{Last}'s effect is
- undefined if @var{list} is empty.
- @lisp
- (last '(a b c)) @result{} c@end lisp
- @end deffn
- @deffn procedure insert object list elt< @returns{} list
- Inserts @var{object} into the sorted list @var{list}, comparing the
- order of @var{object} and each element by @var{elt<}.
- @lisp
- (insert 3 '(0 1 2 4 5) <) @result{} (0 1 2 3 4 5)@end lisp
- @end deffn
- @node Filenames
- @subsection Filenames
- @stindex filenames
- There are some basic filename manipulation facilities exported by the
- @code{filenames} structure.@footnote{The facilities Scheme48 provides
- are very rudimentary, and they are not intended to act as a coherent
- and comprehensive pathname or logical name facility such as that of
- Common Lisp. However, they served the basic needs of Scheme48's build
- process when they were originally created.}
- @defvr constant *scheme-file-type* @returns{} symbol
- @defvrx constant *load-file-type* @returns{} symbol
- @code{*Scheme-file-type*} is a symbol denoting the file extension that
- Scheme48 assumes for Scheme source files; any other extension, for
- instance in the filename list of a structure definition, must be
- written explicitly. @code{*Load-file-type*} is a symbol denoting the
- preferable file extension to load files from. (@code{*Load-file-type*}
- was used mostly in bootstrapping Scheme48 from Pseudoscheme or T long
- ago and is no longer very useful.)
- @end defvr
- @deffn procedure file-name-directory filename @returns{} string
- @deffnx procedure file-name-nondirectory filename @returns{} string
- @code{File-name-directory} returns the directory component of the
- filename denoted by the string @var{filename}, including a trailing
- separator (on Unix, @code{/}). @code{File-name-nondirectory} returns
- everything but the directory component of the filename denoted by the
- string @var{filename}, including the extension.
- @lisp
- (file-name-directory "/usr/local/lib/scheme48/scheme48.image")
- @result{} "/usr/local/lib/scheme48/"
- (file-name-nondirectory "/usr/local/lib/scheme48/scheme48.image")
- @result{} "scheme48.image"
- (file-name-directory "scheme48.image")
- @result{} ""
- (file-name-nondirectory "scheme48.image")
- @result{} "scheme48.image"@end lisp
- @end deffn
- @cindex namelists
- @dfn{Namelists} are platform-independent means by which to name files.
- They are represented as readable S-expressions of any of the following
- forms:
- @table @code
- @item @var{basename}
- represents a filename with only a basename and no directory or file
- type/extension;
- @item (@var{directory} @var{basename} [@var{type}])
- represents a filename with a single preceding directory component and
- an optional file type/extension; and
- @item ((@var{directory} @dots{}) @var{basename} [@var{type}])
- represents a filename with a sequence of directory components, a
- basename, and an optional file type/extension.
- @end table
- Each atomic component --- that is, the basename, the type/extension,
- and each individual directory component --- may be either a string or
- a symbol. Symbols are converted to the canonical case of the host
- operating system by @code{namestring} (on Unix, lowercase); the case of
- string components is not touched.
- @deffn procedure namestring namelist directory default-type @returns{} string
- Converts @var{namelist} to a string in the format required by the host
- operating system.@footnote{However, the current standard distribution
- of Scheme48 is specific to Unix: the current code implements only Unix
- filename facilities.} If @var{namelist} did not have a directory
- component, @var{directory}, a string in the underlying operating
- system's format for directory prefixes, is added to the resulting
- namestring; and, if @var{namelist} did not have a type/extension,
- @var{default-type}, which may be a string or a symbol and which should
- @emph{not} already contain the host operating system's delimiter
- (usually a dot), is appended to the resulting namestring.
- @var{Directory} or @var{default-type} may be @code{#f}, in which case
- they are not prefixed or appended to the resulting filename.
- @lisp
- (namestring 'foo #f #f) @result{} "foo"
- (namestring 'foo "bar" 'baz) @result{} "bar/foo.baz"
- (namestring '(rts defenum) "scheme" 'scm)
- @result{} "scheme/rts/defenum.scm"
- (namestring '((foo bar) baz quux) "zot" #f)
- @result{} "zot/foo/bar/baz.quux"
- (namestring "zot/foo/bar/baz.quux" #f "mumble")
- @result{} "zot/foo/bar/baz.quux.mumble"@end lisp
- @end deffn
- @subsubsection Filename translations
- @cindex filename translations
- Scheme48 keeps a registry of @dfn{filename translations}, translations
- from filename prefixes to the real prefixes. This allows abstraction
- of actual directory prefixes without necessitating running Scheme code
- to construct directory pathnames (for example, in configuration files).
- Interactively, in the usual command processor, users can set filename
- translations with the @command{,translate}; @pxref{Basic commands}.
- @deffn procedure translations @returns{} string/string-alist
- Returns the alist of filename translations.
- @end deffn
- @deffn procedure set-translation! from to @returns{} unspecified
- Adds a filename prefix translation, overwriting an existing one if one
- already existed.
- @end deffn
- @deffn procedure translate filename @returns{} translated-filename
- Translates the first prefix of @var{filename} found in the registry of
- translations and returns the translated filename.
- @end deffn
- @lisp
- (set-translation! "s48" "/home/me/scheme/scheme48/scheme")
- (translate (namestring '(bcomp frame) "s48" 'scm))
- @result{} "/home/me/scheme/scheme48/scheme/bcomp/frame.scm"
- (translate (namestring "comp-packages" "s48" 'scm))
- @result{} "/home/me/scheme/scheme48/scheme/comp-packages.scm"
- (translate "s48/frobozz")
- @result{} "/home/me/scheme/scheme48/scheme/frobozz"
- (set-translation! "scheme48" "s48")
- (translate (namestring '((scheme48 big) filename) #f 'scm))
- @result{} scheme48/big/filename.scm
- (translate (translate (namestring '((scheme48 big) filename) #f 'scm)))
- @result{} "/home/me/scheme/scheme48/scheme/big/filename.scm"@end lisp
- @cindex @code{=scheme48/}
- One filename translation is built-in, mapping @code{=scheme48/} to the
- directory of system files in a Scheme48 installation, which on Unix is
- typically a directory in @code{/usr/local/lib}.
- @lisp
- (translate "=scheme48/scheme48.image")
- @result{} /usr/local/scheme48/scheme48.image@end lisp
- @node Fluid/dynamic bindings
- @subsection Fluid/dynamic bindings
- @cindex fluid bindings
- @cindex dynamic bindings
- @stindex fluids
- The @code{fluids} structure provides a facility for dynamically bound
- resources, like special variables in Common Lisp, but with first-class,
- unforgeable objects.
- Every @embedref{Multithreading,thread} in Scheme48 maintains a
- @dfn{fluid or dynamic environment}. It maps @dfn{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 @code{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 @code{$} (dollar sign); @eg{}, @code{$foo}.
- @deffn procedure make-fluid top-level-value @returns{} fluid
- Fluid constructor.
- @end deffn
- @deffn procedure fluid fl @returns{} value
- @deffnx procedure set-fluid! fl value @returns{} unspecified
- @deffnx procedure fluid-cell-ref fluid-cell @returns{} value
- @deffnx procedure fluid-cell-set! fluid-cell value @returns{} unspecified
- @code{Fluid} returns the value that the current dynamic environment
- associates with @var{fl}, if it has an association; if not, it returns
- @var{fl}'s top-level value, as passed to @code{make-fluid} to create
- @var{fl}. @code{Set-fluid!} assigns the value of the association in
- the current dynamic environment for @var{fl} to @var{value}, or, if
- there is no such association, it assigns the top-level value of
- @var{fl} to @var{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 @embedref{Cells, mutable cells}.
- @code{Fluid-cell-ref} and @code{fluid-cell-set!} are conveniences for
- this; they simply call the corresponding cell operations after
- fetching the cell that the fluid refers to by using @code{fluid}.
- @end deffn
- @deffn procedure let-fluid fluid value thunk @returns{} values
- @deffnx procedure let-fluids fluid@sub{0} value@sub{0} fluid@sub{1} value@sub{1} @dots{} thunk @returns{} values
- These dynamically bind their fluid arguments to the corresponding value
- arguments and apply @var{thunk} with the new dynamic environment,
- restoring the old one after @var{thunk} returns and returning the value
- it returns.
- @end deffn
- @lisp
- (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))
- @result{} (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))
- @print{} initial: 0
- @print{} let-fluid: 1
- @print{} after-let-fluid: 0
- @print{} outer-let-fluid: 1
- @print{} inner-let-fluid: 2
- @print{} let-fluid-within-cont: 1
- @print{} inner-let-fluid-within-cont: 2
- @print{} let-fluid-thrown: 0
- @print{} after-throw: 0@end lisp
- @node ASCII character encoding
- @subsection ASCII character encoding
- @stindex ascii
- These names are exported by the @code{ascii} structure.
- @deffn procedure char->ascii char @returns{} ascii-integer
- @deffnx procedure ascii->char ascii-integer @returns{} character
- These convert characters to and from their integer ASCII encodings.
- @code{Char->ascii} and @code{ascii->char} are similar to R5RS's
- @code{char->integer} and @code{integer->char}, but they are guaranteed
- to use the ASCII encoding. Scheme48's @code{integer->char} and
- @code{char->integer} deliberately do not use the ASCII encoding to
- encourage programmers to make use of only what R5RS guarantees.
- @lisp
- (char->ascii #\a) @result{} 97
- (ascii->char 97) @result{} #\a@end lisp
- @end deffn
- @defvr constant ascii-limit @returns{} integer
- @defvrx constant ascii-whitespaces @returns{} ascii-integer-list
- @code{Ascii-limit} is an integer that is one greater than the highest
- number that @code{char->ascii} may return or @code{ascii->char} will
- accept. @code{Ascii-whitespaces} is a list of the integer encodings of
- all characters that are considered whitespace: space (32), horizontal
- tab (9), line-feed/newline (10), vertical tab (11), form-feed/page (12),
- and carriage return (13).
- @end defvr
- @node Integer enumerations
- @subsection Integer enumerations
- @stindex enumerated
- Scheme48 provides a facility for @dfn{integer enumerations}, somewhat
- akin to C enums. The names described in this section are exported by
- the @code{enumerated} structure.
- @strong{Note:} These enumerations are @emph{not} compatible with the
- @embedref{Enumerated/finite types and sets, enumerated/finite type
- facility}.
- @deffn syntax define-enumeration enumeration-name (enumerand-name @dots{})
- Defines @var{enumeration-name} to be a static enumeration. (Note that
- it is @emph{not} a regular variable. It is actually a macro, though its
- exact syntax is not exposed; it must be exported with the
- @embedref{Static type system, @code{:syntax} type}.)
- @var{Enumeration-name} thereafter may be used with the enumeration
- operators described below.
- @end deffn
- @deffn syntax enum enumeration-name enumerand-name @returns{} enumerand-integer
- @deffnx syntax components enumeration-name @returns{} component-vector
- @code{Enum} expands to the integer value represented symbolically by
- @var{enumerand-name} in the enumeration @var{enumeration-name} as
- defined by @code{define-enumeration}. @code{Components} expands to a
- literal vector of the components in @var{enumeration-name} as defined
- by @code{define-enumeration}. In both cases, @var{enumerand-name} must
- be written literally as the name of the enumerand; see
- @code{name->enumerand} for extracting an enumerand's integer given a
- run-time symbol naming an enumerand.
- @end deffn
- @deffn syntax enumerand->name enumerand-integer enumeration-name @returns{} symbol
- @deffnx syntax name->enumerand enumerand-name enumeration-name @returns{} integer-enumerand
- @code{Enumerand->name} expands to a form that evaluates to the symbolic
- name that the integer value of the expression @var{enumerand-integer}
- is mapped to by @var{enumeration-name} as defined by
- @code{define-enumeration}. @code{Name->enumerand} expands to a form
- that evaluates to the integer value of the enumerand in
- @var{enumeration-name} that is represented symbolically by the value of
- the expression @var{enumerand-name}.
- @end deffn
- @stindex enum-case
- The @code{enum-case} structure provides a handy utility of the same
- name for dispatching on enumerands.
- @deffn syntax enum-case
- @lisp
- (enum-case @var{enumeration-name} @var{key}
- ((@var{enumerand-name} @dots{}) @var{body})
- @dots{}
- [(else @var{else-body})])@end lisp
- Matches @var{key} with the clause one of whose names maps in
- @var{enumeration-name} to the integer value of @var{key}. @var{Key}
- must be an exact, non-negative integer. If no matching clause is
- found, and @var{else-body} is present, @code{enum-case} will evaluate
- @var{else-body}; if @var{else-body} is not present, @code{enum-case}
- will return an unspecific value.
- @end deffn
- Examples:
- @lisp
- (define-enumeration foo
- (bar
- baz))
- (enum foo bar) @result{} 0
- (enum foo baz) @result{} 1
- (enum-case foo (enum foo bar)
- ((baz) 'x)
- (else 'y))
- @result{} y
- (enum-case foo (enum foo baz)
- ((bar) 'a)
- ((baz) 'b))
- @result{} b
- (enumerand->name 1 foo) @result{} baz
- (name->enumerand 'bar foo) @result{} 0
- (components foo) @result{} #(bar baz)@end lisp
- @c Include the sections on the various kinds of data structures.
- @include system/data.texi
- @node Type annotations
- @subsection Type annotations
- @cindex type system loopholes
- @cindex loopholes in the type system
- @stindex loopholes
- Scheme48 allows optional type annotations with the @code{loophole}
- special form from the @code{loopholes} structure.
- @deffn syntax loophole type expression @returns{} values
- This is exactly equivalent in semantics to @var{expression}, except the
- static type analyzer is informed that the whole expression has the type
- @var{type}. For details on the form of @var{type}, @pxref{Static type
- system}.
- @end deffn
- Type annotations can be used for several different purposes:
- @itemize @bullet
- @item
- simply to give more information to the static type analyzer;
- @item
- to work as a simple abstract data type facility: passing a type name
- that does not already exist creates a new disjoint value type; and
- @item
- to prevent the type system from generating warnings in the rare cases
- where it would do so incorrectly, such as in the @code{primitive-cwcc},
- @code{primitive-catch}, and @code{with-continuation} devices (to be
- documented in a later edition of this manual).
- @end itemize
- To see an example of the second use, see @file{rts/jar-defrecord.scm}
- in Scheme48's source tree.
- @strong{Note:} Type annotations do @emph{not} damage the safety of
- Scheme's type system. They affect only the static type analyzer, which
- does not change run-time object representations; it only checks type
- soundness of code and generates warnings for programs that would cause
- run-time type errors.
- @node Explicit renaming macros
- @subsection Explicit renaming macros
- @cindex low-level macros
- @cindex macros, low-level
- @cindex unhygienic macros
- @cindex macros, unhygienic
- Scheme48 supports a simple low-level macro system based on explicitly
- renaming identifiers to preserve hygiene. The macro system is
- well-integrated with the module system; @pxref{Macros in concert with
- modules}.
- @dfn{Explicit renaming} macro transformers operate on simple
- S-expressions extended with @dfn{identifiers}, which are like symbols
- but contain more information about lexical context. In order to
- preserve that lexical context, transformers must explicitly call a
- @dfn{renamer} procedure to produce an identifier with the proper scope.
- To test whether identifiers have the same denotation, transformers are
- also given an identifier comparator.
- The facility provided by Scheme48 is almost identical to the explicit
- renaming macro facility described in [Clinger 91].@footnote{For the
- sake of avoiding any potential copyright issues, the paper is not
- duplicated here, and instead the author of this manual has written the
- entirety of this section.} It differs only by the @code{transformer}
- keyword, which is described in the paper but not used by Scheme48, and
- in the annotation of auxiliary names.
- @deffn syntax define-syntax name transformer [aux-names]
- Introduces a derived syntax @var{name} with the given transformer,
- which may be an explicit renaming transformer procedure, a pair whose
- car is such a procedure and whose cdr is a list of auxiliary
- identifiers, or the value of a @code{syntax-rules} expression. In the
- first case, the added operand @var{aux-names} may, and usually should
- except in the case of local (non-exported) syntactic bindings, be a
- list of all of the auxiliary top-level identifiers used by the macro.
- @end deffn
- Explicit renaming transformer procedures are procedures of three
- arguments: an input form, an identifier renamer procedure, and an
- identifier comparator procedure. The input form is the whole form of
- the macro's invocation (including, at the car, the identifier whose
- denotation was the syntactic binding). The identifier renamer accepts
- an identifier as an argument and returns an identifier that is
- hygienically renamed to refer absolutely to the identifier's denotation
- in the environment of the macro's definition, not in the environment of
- the macro's usage. In order to preserve hygiene of syntactic
- transformations, macro transformers must call this renamer procedure
- for any literal identifiers in the output. The renamer procedure is
- referentially transparent; that is, two invocations of it with the same
- arguments in terms of @code{eq?} will produce the same results in the
- sense of @code{eq?}.
- For example, this simple transformer for a @code{swap!} macro is
- incorrect:
- @lisp
- (define-syntax swap!
- (lambda (form rename compare)
- (let ((a (cadr form))
- (b (caddr form)))
- `(LET ((TEMP ,a))
- (SET! ,a ,b)
- (SET! ,b TEMP)))))@end lisp
- @noindent
- The introduction of the literal identifier @code{temp} into the output
- may conflict with one of the input variables if it were to also be
- named @code{temp}: @code{(swap! temp foo)} or @code{(swap! bar temp)}
- would produce the wrong result. Also, the macro would fail in another
- very strange way if the user were to have a local variable named
- @code{let} or @code{set!}, or it would simply produce invalid output if
- there were no binding of @code{let} or @code{set!} in the environment
- in which the macro was used. These are basic problems of abstraction:
- the user of the macro should not need to know how the macro is
- internally implemented, notably with a @code{temp} variable and using
- the @code{let} and @code{set!} special forms.
- Instead, the macro must hygienically rename these identifiers using
- the renamer procedure it is given, and it should list the top-level
- identifiers it renames (which cannot otherwise be extracted
- automatically from the macro's definition):
- @lisp
- (define-syntax swap!
- (lambda (form rename compare)
- (let ((a (cadr form))
- (b (caddr form)))
- `(,(rename 'LET) ((,(rename 'TEMP) ,a))
- (,(rename 'SET!) ,a ,b)
- (,(rename 'SET!) ,b ,(rename 'TEMP)))))
- (LET SET!))@end lisp
- However, some macros are unhygienic by design, @ie{} they insert
- identifiers into the output intended to be used in the environment of
- the macro's usage. For example, consider a @code{loop} macro that
- loops endlessly, but binds a variable named @code{exit} to an escape
- procedure to the continuation of the @code{loop} expression, with
- which the user of the macro can escape the loop:
- @lisp
- (define-syntax loop
- (lambda (form rename compare)
- (let ((body (cdr form)))
- `(,(rename 'CALL-WITH-CURRENT-CONTINUATION)
- (,(rename 'LAMBDA) (EXIT) ; Literal, unrenamed EXIT.
- (,(rename 'LET) ,(rename 'LOOP) ()
- ,@@body
- (,(rename 'LOOP)))))))
- (CALL-WITH-CURRENT-CONTINUATION LAMBDA LET))@end lisp
- Note that macros that expand to @code{loop} must also be unhygienic;
- for instance, this na@"{@dotless{i}}ve definition of a
- @code{loop-while} macro is incorrect, because it hygienically renames
- @code{exit} automatically by of the definition of @code{syntax-rules},
- so the identifier it refers to is not the one introduced
- unhygienically by @code{loop}:
- @lisp
- (define-syntax loop-while
- (syntax-rules ()
- ((LOOP-WHILE test body ...)
- (LOOP (IF (NOT test)
- (EXIT)) ; Hygienically renamed.
- body ...))))@end lisp
- @noindent
- Instead, a transformer must be written to not hygienically rename
- @code{exit} in the output:
- @lisp
- (define-syntax loop-while
- (lambda (form rename compare)
- (let ((test (cadr form))
- (body (cddr form)))
- `(,(rename 'LOOP)
- (,(rename 'IF) (,(rename 'NOT) ,test)
- (EXIT)) ; Not hygienically renamed.
- ,@@body)))
- (LOOP IF NOT))@end lisp
- To understand the necessity of annotating macros with the list of
- auxiliary names they use, consider the following definition of the
- @code{delay} form, which transforms @code{(delay @var{exp})} into
- @code{(make-promise (lambda () @var{exp}))}, where @code{make-promise}
- is some non-exported procedure defined in the same module as the
- @code{delay} macro:
- @lisp
- (define-syntax delay
- (lambda (form rename compare)
- (let ((exp (cadr form)))
- `(,(rename 'MAKE-PROMISE) (,(rename 'LAMBDA) () ,exp)))))@end lisp
- @noindent
- This preserves hygiene as necessary, but, while the compiler can know
- whether @code{make-promise} is @emph{exported} or not, it cannot in
- general determine whether @code{make-promise} is @emph{local}, @ie{}
- not accessible in any way whatsoever, even in macro output, from any
- other modules. In this case, @code{make-promise} is @emph{not} local,
- but the compiler cannot in general know this, and it would be an
- unnecessarily heavy burden on the compiler, the linker, and related
- code-processing systems to assume that all bindings are not local. It
- is therefore better@footnote{However, the current compiler in Scheme48
- does not require this, though the static linker does.} to annotate such
- definitions with the list of auxiliary names used by the transformer:
- @lisp
- (define-syntax delay
- (lambda (form rename compare)
- (let ((exp (cadr form)))
- `(,(rename 'MAKE-PROMISE) (,(rename 'LAMBDA) () ,exp))))
- (MAKE-PROMISE LAMBDA))@end lisp
|