From f24b9140d6f74804d5599ec225717d38ca443813 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 20 Feb 2017 00:05:26 -0800 Subject: Import Upstream version 2c0 --- slib.texi | 16015 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 8837 insertions(+), 7178 deletions(-) (limited to 'slib.texi') diff --git a/slib.texi b/slib.texi index 1d41fdc..9251b9f 100644 --- a/slib.texi +++ b/slib.texi @@ -5,6 +5,9 @@ @setchapternewpage on @c Choices for setchapternewpage are {on,off,odd}. @paragraphindent 2 +@defcodeindex ft +@syncodeindex ft cp +@syncodeindex tp cp @c %**end of header @iftex @@ -17,8 +20,8 @@ @ifinfo This file documents SLIB, the portable Scheme library. -Copyright (C) 1993 Todd R. Eigenschink -Copyright (C) 1993, 1994, 1995 Aubrey Jaffer +Copyright (C) 1993 Todd R. Eigenschink@* +Copyright (C) 1993, 1994, 1995, 1996, 1997 Aubrey Jaffer Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -45,13 +48,13 @@ by the author. @titlepage @title SLIB @subtitle The Portable Scheme Library -@subtitle Version 2a3 -@subtitle June 1995 -@author by Todd R. Eigenschink, Dave Love, and Aubrey Jaffer +@subtitle Version 2c0 +@author by Aubrey Jaffer @page @vskip 0pt plus 1filll -Copyright @copyright{} 1993, 1994, 1995 Todd R. Eigenschink and Aubrey Jaffer +Copyright @copyright{} 1993 Todd R. Eigenschink@* +Copyright @copyright{} 1993, 1994, 1995, 1996, 1997 Aubrey Jaffer Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -69,7577 +72,9112 @@ by the author. @end titlepage - - - -@node Top, Overview, (dir), (dir) +@node Top, The Library System, (dir), (dir) @ifinfo -This file documents SLIB, the portable Scheme library. +@cindex SLIB +@dfn{SLIB} is a portable library for the programming language +@cindex Scheme +@dfn{Scheme}. It provides a platform independent framework for using +@dfn{packages} of Scheme procedures and syntax. +@cindex packages +@cindex package +As distributed, SLIB contains useful packages for all implementations. +Its catalog can be transparently extended to accomodate packages +specific to a site, implementation, user, or directory. -@heading Good Engineering is 1% inspiration and 99% documentation. - -Herein lies the good part. Many thanks to Todd Eigenschink - (who thanks Dave Love ) -for creating @file{slib.texi}. I have learned much from their example. - -Aubrey Jaffer -jaffer@@ai.mit.edu +@quotation +Aubrey Jaffer @* +@i{Hyperactive Software} -- The Maniac Inside!@* +http://www-swiss.ai.mit.edu/~jaffer/SLIB.html +@end quotation @end ifinfo - @menu -* Overview:: What is SLIB? - -* Data Structures:: Various data structures. -* Macros:: Extensions to Scheme syntax. -* Numerics:: -* Procedures:: Miscellaneous utility procedures. -* Standards Support:: Support for Scheme Standards. -* Session Support:: Debugging, Pathnames, Require, etc. - -* Optional SLIB Packages:: -* Procedure and Macro Index:: -* Variable Index:: +* The Library System:: How to use and customize. +* Scheme Syntax Extension Packages:: +* Textual Conversion Packages:: +* Mathematical Packages:: +* Database Packages:: +* Other Packages:: +* About SLIB:: Install, etc. +* Index:: @end menu +@node The Library System, Scheme Syntax Extension Packages, Top, Top +@chapter The Library System -@node Overview, Data Structures, Top, Top -@chapter Overview - -SLIB is a portable Scheme library meant to provide compatibility and -utility functions for all standard Scheme implementations, and fixes -several implementations which are non-conforming. SLIB conforms to -@cite{Revised^4 Report on the Algorithmic Language Scheme} and the IEEE -P1178 specification. SLIB supports Unix and similar systems, VMS, and -MS-DOS.@refill +@iftex +@section Introduction -For a summary of what each file contains, see the file @file{README}. -For a list of the features that have changed since the last SLIB -release, see the file @file{ANNOUNCE}. For a list of the features that -have changed over time, see the file @file{ChangeLog}. +@noindent +@cindex SLIB +@dfn{SLIB} is a portable library for the programming language +@cindex Scheme +@dfn{Scheme}. It provides a platform independent framework for using +@dfn{packages} of Scheme procedures and syntax. +@cindex packages +@cindex package +As distributed, SLIB contains useful packages for all implementations. +Its catalog can be transparently extended to accomodate packages +specific to a site, implementation, user, or directory. -The maintainer can be reached as @samp{jaffer@@ai.mit.edu}. +@quotation +Aubrey Jaffer @* +@i{Hyperactive Software} -- The Maniac Inside!@* +@ifset html + +@end ifset +http://www-swiss.ai.mit.edu/~jaffer/SLIB.html +@ifset html + +@end ifset +@end quotation +@end iftex @menu -* Installation:: How to install SLIB on your system. -* Porting:: SLIB to new platforms -* Coding Standards:: How to write modules for SLIB. -* Copyrights:: Intellectual propery issues. -* Manual Conventions:: Conventions used in this manual. +* Feature:: SLIB names. +* Requesting Features:: +* Library Catalogs:: +* Catalog Compilation:: +* Built-in Support:: +* About this manual:: @end menu -@node Installation, Porting, Overview, Overview -@section Installation -Check the manifest in @file{README} to find a configuration file for -your Scheme implementation. Initialization files for most IEEE P1178 -compliant Scheme Implementations are included with this distribution. +@node Feature, Requesting Features, The Library System, The Library System +@section Feature -If the Scheme implementation supports @code{getenv}, then the value of -the shell environment variable @var{SCHEME_LIBRARY_PATH} will be used -for @code{(library-vicinity)} if it is defined. Currently, Chez, Elk, -MITScheme, scheme->c, VSCM, and SCM support @code{getenv}. +@noindent +@cindex feature +SLIB denotes @dfn{features} by symbols. SLIB maintains a list of +features supported by the Scheme @dfn{session}. The set of features +@cindex session +provided by a session may change over time. Some features are +properties of the Scheme implementation being used. The following +features detail what sort of numbers are available from an +implementation. -You should check the definitions of @code{software-type}, -@code{scheme-implementation-version}, -@iftex -@* -@end iftex -@code{implementation-vicinity}, -and @code{library-vicinity} in the initialization file. There are -comments in the file for how to configure it. +@itemize @bullet +@item +'inexact +@item +'rational +@item +'real +@item +'complex +@item +'bignum +@end itemize -Once this is done you can modify the startup file for your Scheme -implementation to @code{load} this initialization file. SLIB is then -installed. +@noindent +Other features correspond to the presence of sets of Scheme procedures +or syntax (macros). -Multiple implementations of Scheme can all use the same SLIB directory. -Simply configure each implementation's initialization file as outlined -above. +@defun provided? feature +Returns @code{#t} if @var{feature} is supported by the current Scheme +session. +@end defun -The SCM implementation does not require any initialization file as SLIB -support is already built in to SCM. See the documentation with SCM for -installation instructions. +@deffn Procedure provide feature +Informs SLIB that @var{feature} is supported. Henceforth +@code{(provided? @var{feature})} will return @code{#t}. +@end deffn -SLIB includes methods to create heap images for the VSCM and Scheme48 -implementations. The instructions for creating a VSCM image are in -comments in @file{vscm.init}. To make a Scheme48 image, @code{cd} to -the SLIB directory and type @code{make slib48}. This will also create a -shell script with the name @code{slib48} which will invoke the saved -image. +@example +(provided? 'foo) @result{} #f +(provide 'foo) +(provided? 'foo) @result{} #t +@end example -@node Porting, Coding Standards, Installation, Overview -@section Porting -If there is no initialization file for your Scheme implementation, you -will have to create one. Your Scheme implementation must be largely -compliant with @cite{IEEE Std 1178-1990} or @cite{Revised^4 Report on -the Algorithmic Language Scheme} to support SLIB. +@node Requesting Features, Library Catalogs, Feature, The Library System +@section Requesting Features -@file{Template.scm} is an example configuration file. The comments -inside will direct you on how to customize it to reflect your system. -Give your new initialization file the implementation's name with -@file{.init} appended. For instance, if you were porting -@code{foo-scheme} then the initialization file might be called -@file{foo.init}. +@noindent +@cindex catalog +SLIB creates and maintains a @dfn{catalog} mapping features to locations +of files introducing procedures and syntax denoted by those features. -Your customized version should then be loaded as part of your scheme -implementation's initialization. It will load @file{require.scm} -(@xref{Require}) from the library; this will allow the use of -@code{provide}, @code{provided?}, and @code{require} along with the -@dfn{vicinity} functions (@code{vicinity} functions are documented in -the section on Require. @xref{Require}). The rest of the library will -then be accessible in a system independent fashion.@refill +@noindent +At the beginning of each section of this manual, there is a line like +@code{(require '@var{feature})}. +@ftindex feature +The Scheme files comprising SLIB are cataloged so that these feature +names map to the corresponding files. -Please mail new working configuration files to @code{jaffer@@ai.mit.edu} -so that they can be included in the SLIB distribution.@refill +@noindent +SLIB provides a form, @code{require}, which loads the files providing +the requested feature. -@node Coding Standards, Copyrights, Porting, Overview -@section Coding Standards +@deffn Procedure require feature +@itemize @bullet +@item +If @code{(provided? @var{feature})} is true, +then @code{require} just returns an unspecified value. +@item +Otherwise, if @var{feature} is found in the catalog, then the +corresponding files will be loaded and an unspecified value returned. -All library packages are written in IEEE P1178 Scheme and assume that a -configuration file and @file{require.scm} package have already been -loaded. Other versions of Scheme can be supported in library packages -as well by using, for example, @code{(provided? 'rev3-report)} or -@code{(require 'rev3-report)} (@xref{Require}).@refill +Subsequently @code{(provided? @var{feature})} will return @code{#t}. +@item +Otherwise (@var{feature} not found in the catalog), an error is +signaled. +@end itemize +@end deffn -@file{require.scm} defines @code{*catalog*}, an association list of -module names and filenames. When a new package is added to the library, -an entry should be added to @file{require.scm}. Local packages can also -be added to @code{*catalog*} and even shadow entries already in the -table.@refill +@noindent +The catalog can also be queried using @code{require:feature->path}. -The module name and @samp{:} should prefix each symbol defined in the -package. Definitions for external use should then be exported by having -@code{(define foo module-name:foo)}.@refill +@defun require:feature->path feature +@itemize @bullet +@item +If @var{feature} is already provided, then returns @code{#t}. +@item +Otherwise, if @var{feature} is in the catalog, the path or list of paths +associated with @var{feature} is returned. +@item +Otherwise, returns @code{#f}. +@end itemize +@end defun -Submitted code should not duplicate routines which are already in SLIB -files. Use @code{require} to force those features to be supported in -your package. Care should be taken that there are no circularities in -the @code{require}s and @code{load}s between the library -packages.@refill -Documentation should be provided in Emacs Texinfo format if possible, -But documentation must be provided. +@node Library Catalogs, Catalog Compilation, Requesting Features, The Library System +@section Library Catalogs -Your package will be released sooner with SLIB if you send me a file -which tests your code. Please run this test @emph{before} you send me -the code! +@noindent +At the start of a session no catalog is present, but is created with the +first catalog inquiry (such as @code{(require 'random)}). Several +sources of catalog information are combined to produce the catalog: -@subheading Modifications +@itemize @bullet +@item +standard SLIB packages. +@item +additional packages of interest to this site. +@item +packages specifically for the variety of Scheme which this +session is running. +@item +packages this user wants to always have available. This catalog is the +file @file{homecat} in the user's @dfn{HOME} directory. +@cindex HOME +@item +packages germane to working in this (current working) directory. This +catalog is the file @file{usercat} in the directory to which it applies. +One would typically @code{cd} to this directory before starting the +Scheme session. +@end itemize -Please document your changes. A line or two for @file{ChangeLog} is -sufficient for simple fixes or extensions. Look at the format of -@file{ChangeLog} to see what information is desired. Please send me -@code{diff} files from the latest SLIB distribution (remember to send -@code{diff}s of @file{slib.texi} and @file{ChangeLog}). This makes for -less email traffic and makes it easier for me to integrate when more -than one person is changing a file (this happens a lot with -@file{slib.texi} and @samp{*.init} files). +@noindent +Catalog files consist of one or more @dfn{association list}s. +@cindex Catalog File +In the circumstance where a feature symbol appears in more than one +list, the latter list's association is retrieved. Here are the +supported formats for elements of catalog lists: -If someone else wrote a package you want to significantly modify, please -try to contact the author, who may be working on a new version. This -will insure against wasting effort on obsolete versions. +@table @code +@item (@var{feature} . @i{}) +Redirects to the feature named @i{}. +@item (@var{feature} . "@i{}") +Loads file @i{}. +@item (@var{feature} source "@i{"}) +@code{slib:load}s the Scheme source file @i{}. +@item (@var{feature} compiled "@i{"} @dots{}) +@code{slib:load-compiled}s the files @i{} @dots{}. +@end table -Please @emph{do not} reformat the source code with your favorite -beautifier, make 10 fixes, and send me the resulting source code. I do -not have the time to fish through 10000 diffs to find your 10 real fixes. +@noindent +The various macro styles first @code{require} the named macro package, +then just load @i{} or load-and-macro-expand @i{} as +appropriate for the implementation. -@node Copyrights, Manual Conventions, Coding Standards, Overview -@section Copyrights +@table @code +@item (@var{feature} defmacro "@i{"}) +@code{defmacro:load}s the Scheme source file @i{}. +@item (@var{feature} macro-by-example "@i{"}) +@code{defmacro:load}s the Scheme source file @i{}. +@end table -This section has instructions for SLIB authors regarding copyrights. +@table @code +@item (@var{feature} macro "@i{"}) +@code{macro:load}s the Scheme source file @i{}. +@item (@var{feature} macros-that-work "@i{"}) +@code{macro:load}s the Scheme source file @i{}. +@item (@var{feature} syntax-case "@i{"}) +@code{macro:load}s the Scheme source file @i{}. +@item (@var{feature} syntactic-closures "@i{"}) +@code{macro:load}s the Scheme source file @i{}. +@end table -Each package in SLIB must either be in the public domain, or come with a -statement of terms permitting users to copy, redistribute and modify it. -The comments at the beginning of @file{require.scm} and -@file{macwork.scm} illustrate copyright and appropriate terms. +@noindent +Here is an example of a @file{usercat} catalog. A Program in this +directory can invoke the @samp{run} feature with @code{(require 'run)}. -If your code or changes amount to less than about 10 lines, you do not -need to add your copyright or send a disclaimer. +@example +;;; "usercat": SLIB catalog additions for SIMSYNCH. -*-scheme-*- -@subheading Putting code into the Public Domain +( + (simsynch . "../synch/simsynch.scm") + (run . "../synch/run.scm") + (schlep . "schlep.scm") +) +@end example -In order to put code in the public domain you should sign a copyright -disclaimer and send it to the SLIB maintainer. Contact -jaffer@@ai.mit.edu for the address to mail the disclaimer to. -@quotation -I, @var{name}, hereby affirm that I have placed the software package -@var{name} in the public domain. +@node Catalog Compilation, Built-in Support, Library Catalogs, The Library System +@section Catalog Compilation -I affirm that I am the sole author and sole copyright holder for the -software package, that I have the right to place this software package -in the public domain, and that I will do nothing to undermine this -status in the future. -@flushright - @var{signature and date} -@end flushright -@end quotation +@noindent +SLIB combines the catalog information which doesn't vary per user into +the file @file{slibcat} in the implementation-vicinity. Therefore +@file{slibcat} needs change only when new software is installed or +compiled. Because the actual pathnames of files can differ from +installation to installation, SLIB builds a separate catalog for each +implementation it is used with. -This wording assumes that you are the sole author. If you are not the -sole author, the wording needs to be different. If you don't want to be -bothered with sending a letter every time you release or modify a -module, make your letter say that it also applies to your future -revisions of that module. +@noindent +The definition of @code{*SLIB-VERSION*} in SLIB file @file{require.scm} +is checked against the catalog association of @code{*SLIB-VERSION*} to +ascertain when versions have changed. I recommend that the definition +of @code{*SLIB-VERSION*} be changed whenever the library is changed. If +multiple implementations of Scheme use SLIB, remember that recompiling +one @file{slibcat} will fix only that implementation's catalog. -Make sure no employer has any claim to the copyright on the work you are -submitting. If there is any doubt, create a copyright disclaimer and -have your employer sign it. Mail the signed disclaimer to the SLIB -maintainer. Contact jaffer@@ai.mit.edu for the address to mail the -disclaimer to. An example disclaimer follows. +@noindent +The compilation scripts of Scheme implementations which work with SLIB +can automatically trigger catalog compilation by deleting +@file{slibcat} or by invoking a special form of @code{require}: -@subheading Explicit copying terms +@deffn Procedure require @r{'new-catalog} +This will load @file{mklibcat}, which compiles and writes a new +@file{slibcat}. +@end deffn @noindent -If you submit more than about 10 lines of code which you are not placing -into the Public Domain (by sending me a disclaimer) you need to: +Another special form of @code{require} erases SLIB's catalog, forcing it +to be reloaded the next time the catalog is queried. -@itemize @bullet -@item -Arrange that your name appears in a copyright line for the appropriate -year. Multiple copyright lines are acceptable. -@item -With your copyright line, specify any terms you require to be different -from those already in the file. -@item -Make sure no employer has any claim to the copyright on the work you are -submitting. If there is any doubt, create a copyright disclaimer and -have your employer sign it. Mail the signed disclaim to the SLIB -maintainer. Contact jaffer@@ai.mit.edu for the address to mail the -disclaimer to. -@end itemize +@deffn Procedure require @r{#f} +Removes SLIB's catalog information. This should be done before saving +an executable image so that, when restored, its catalog will be loaded +afresh. +@end deffn -@subheading Example: Company Copyright Disclaimer +@noindent +Each file in the table below is descibed in terms of its +file-system independent @dfn{vicinity} (@pxref{Vicinity}). The entries +of a catalog in the table override those of catalogs above it in the +table. -This disclaimer should be signed by a vice president or general manager -of the company. If you can't get at them, anyone else authorized to -license out software produced there will do. Here is a sample wording: +@table @asis -@quotation -@var{employer} Corporation hereby disclaims all copyright -interest in the program @var{program} written by @var{name}. +@item @code{implementation-vicinity} @file{slibcat} +@cindex slibcat +This file contains the associations for the packages comprising SLIB, +the @file{implcat} and the @file{sitecat}s. The associations in the +other catalogs override those of the standard catalog. -@var{employer} Corporation affirms that it has no other intellectual -property interest that would undermine this release, and will do nothing -to undermine it in the future. +@item @code{library-vicinity} @file{mklibcat.scm} +@cindex mklibcat.scm +creates @file{slibcat}. -@flushleft -@var{signature and date}, -@var{name}, @var{title}, @var{employer} Corporation -@end flushleft -@end quotation +@item @code{library-vicinity} @file{sitecat} +@cindex sitecat +This file contains the associations specific to an SLIB installation. + +@item @code{implementation-vicinity} @file{implcat} +@cindex implcat +This file contains the associations specific to an implementation of +Scheme. Different implementations of Scheme should have different +@code{implementation-vicinity}. + +@item @code{implementation-vicinity} @file{mkimpcat.scm} +@cindex mkimpcat.scm +if present, creates @file{implcat}. -@node Manual Conventions, , Copyrights, Overview -@section Manual Conventions +@item @code{implementation-vicinity} @file{sitecat} +@cindex sitecat +This file contains the associations specific to a Scheme implementation +installation. -Things that are labeled as Functions are called for their return values. -Things that are labeled as Procedures are called primarily for their -side effects. +@item @code{home-vicinity} @file{homecat} +@cindex homecat +This file contains the associations specific to an SLIB user. -All examples throughout this text were produced using the @code{scm} -Scheme implementation. +@item @code{user-vicinity} @file{usercat} +@cindex usercat +This file contains associations effecting only those sessions whose +@dfn{working directory} is @code{user-vicinity}. -At the beginning of each section, there is a line that looks something -like +@end table -@code{(require 'feature)}. +@node Built-in Support, About this manual, Catalog Compilation, The Library System +@section Built-in Support @noindent -This means that, in order to use @code{feature}, you must include the -line @code{(require 'feature)} somewhere in your code prior to the use -of that feature. @code{require} will make sure that the feature is -loaded.@refill +The procedures described in these sections are supported by all +implementations as part of the @samp{*.init} files or by +@file{require.scm}. +@menu +* Require:: Module Management +* Vicinity:: Pathname Management +* Configuration:: Characteristics of Scheme Implementation +* Input/Output:: Things not provided by the Scheme specs. +* Legacy:: +* System:: LOADing, EVALing, ERRORing, and EXITing +@end menu +@node Require, Vicinity, Built-in Support, Built-in Support +@subsection Require +@defvar *features* +Is a list of symbols denoting features supported in this implementation. +@var{*features*} can grow as modules are @code{require}d. +@var{*features*} must be defined by all implementations +(@pxref{Porting}). -@node Data Structures, Macros, Overview, Top -@chapter Data Structures +Here are features which SLIB (@file{require.scm}) adds to +@var{*features*} when appropriate. +@itemize @bullet +@item +'inexact +@item +'rational +@item +'real +@item +'complex +@item +'bignum +@end itemize +For each item, @code{(provided? '@var{feature})} will return @code{#t} +if that feature is available, and @code{#f} if not. +@end defvar -@menu -* Arrays:: 'array -* Array Mapping:: 'array-for-each -* Association Lists:: 'alist -* Collections:: 'collect -* Dynamic Data Type:: 'dynamic -* Hash Tables:: 'hash-table -* Hashing:: 'hash, 'sierpinski, 'soundex -* Chapter Ordering:: 'chapter-order -* Object:: 'object -* Parameter lists:: 'parameters -* Priority Queues:: 'priority-queue -* Queues:: 'queue -* Records:: 'record -* Base Table:: -* Relational Database:: 'relational-database -* Weight-Balanced Trees:: 'wt-tree -* Structures:: 'struct, 'structure -@end menu +@defvar *modules* +Is a list of pathnames denoting files which have been loaded. +@end defvar +@defvar *catalog* +Is an association list of features (symbols) and pathnames which will +supply those features. The pathname can be either a string or a pair. +If pathname is a pair then the first element should be a macro feature +symbol, @code{source}, or @code{compiled}. The cdr of the pathname +should be either a string or a list. +@end defvar +@noindent +In the following functions if the argument @var{feature} is not a symbol +it is assumed to be a pathname.@refill +@defun provided? feature +Returns @code{#t} if @var{feature} is a member of @code{*features*} or +@code{*modules*} or if @var{feature} is supported by a file already +loaded and @code{#f} otherwise.@refill +@end defun -@node Arrays, Array Mapping, Data Structures, Data Structures -@section Arrays +@deffn Procedure require feature +@var{feature} is a symbol. If @code{(provided? @var{feature})} is true +@code{require} returns. Otherwise, if @code{(assq @var{feature} +*catalog*)} is not @code{#f}, the associated files will be loaded and +@code{(provided? @var{feature})} will henceforth return @code{#t}. An +unspecified value is returned. If @var{feature} is not found in +@code{*catalog*}, then an error is signaled. + +@deffnx Procedure require pathname +@var{pathname} is a string. If @var{pathname} has not already been given as +an argument to @code{require}, @var{pathname} is loaded. +An unspecified value is returned. +@end deffn -@code{(require 'array)} +@deffn Procedure provide feature +Assures that @var{feature} is contained in @code{*features*} if +@var{feature} is a symbol and @code{*modules*} otherwise.@refill +@end deffn -@defun array? obj -Returns @code{#t} if the @var{obj} is an array, and @code{#f} if not. +@defun require:feature->path feature +Returns @code{#t} if @var{feature} is a member of @code{*features*} or +@code{*modules*} or if @var{feature} is supported by a file already +loaded. Returns a path if one was found in @code{*catalog*} under the +feature name, and @code{#f} otherwise. The path can either be a string +suitable as an argument to load or a pair as described above for +*catalog*. @end defun -@defun make-array initial-value bound1 bound2 @dots{} -Creates and returns an array that has as many dimensins as there are -@var{bound}s and fills it with @var{initial-value}.@refill -@end defun -When constructing an array, @var{bound} is either an inclusive range of -indices expressed as a two element list, or an upper bound expressed as -a single integer. So@refill -@lisp -(make-array 'foo 3 3) @equiv{} (make-array 'foo '(0 2) '(0 2)) -@end lisp -@defun make-shared-array array mapper bound1 bound2 @dots{} -@code{make-shared-array} can be used to create shared subarrays of other -arrays. The @var{mapper} is a function that translates coordinates in -the new array into coordinates in the old array. A @var{mapper} must be -linear, and its range must stay within the bounds of the old array, but -it can be otherwise arbitrary. A simple example:@refill -@lisp -(define fred (make-array #f 8 8)) -(define freds-diagonal - (make-shared-array fred (lambda (i) (list i i)) 8)) -(array-set! freds-diagonal 'foo 3) -(array-ref fred 3 3) - @result{} FOO -(define freds-center - (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) - 2 2)) -(array-ref freds-center 0 0) - @result{} FOO -@end lisp + +@node Vicinity, Configuration, Require, Built-in Support +@subsection Vicinity + +@noindent +A vicinity is a descriptor for a place in the file system. Vicinities +hide from the programmer the concepts of host, volume, directory, and +version. Vicinities express only the concept of a file environment +where a file name can be resolved to a file in a system independent +manner. Vicinities can even be used on @dfn{flat} file systems (which +have no directory structure) by having the vicinity express constraints +on the file name. On most systems a vicinity would be a string. All of +these procedures are file system dependent. + +@noindent +These procedures are provided by all implementations. + +@defun make-vicinity filename +Returns the vicinity of @var{filename} for use by @code{in-vicinity}. @end defun -@defun array-rank obj -Returns the number of dimensions of @var{obj}. If @var{obj} is not an -array, 0 is returned. +@defun program-vicinity +Returns the vicinity of the currently loading Scheme code. For an +interpreter this would be the directory containing source code. For a +compiled system (with multiple files) this would be the directory where +the object or executable files are. If no file is currently loading it +the result is undefined. @strong{Warning:} @code{program-vicinity} can +return incorrect values if your program escapes back into a +@code{load}.@refill @end defun -@defun array-shape array -@code{array-shape} returns a list of inclusive bounds. So: -@lisp -(array-shape (make-array 'foo 3 5)) - @result{} ((0 2) (0 4)) -@end lisp +@defun library-vicinity +Returns the vicinity of the shared Scheme library. @end defun -@defun array-dimensions array -@code{array-dimensions} is similar to @code{array-shape} but replaces -elements with a 0 minimum with one greater than the maximum. So: -@lisp -(array-dimensions (make-array 'foo 3 5)) - @result{} (3 5) -@end lisp +@defun implementation-vicinity +Returns the vicinity of the underlying Scheme implementation. This +vicinity will likely contain startup code and messages and a compiler. @end defun -@deffn Procedure array-in-bounds? array index1 index2 @dots{} -Returns @code{#t} if its arguments would be acceptable to -@code{array-ref}. -@end deffn +@defun user-vicinity +Returns the vicinity of the current directory of the user. On most +systems this is @file{""} (the empty string). +@end defun -@defun array-ref array index1 index2 @dots{} -Returns the element at the @code{(@var{index1}, @var{index2})} element -in @var{array}.@refill +@defun home-vicinity +Returns the vicinity of the user's @dfn{HOME} directory, the directory +@cindex HOME +which typically contains files which customize a computer environment +for a user. If scheme is running without a user (eg. a daemon) or if +this concept is meaningless for the platform, then @code{home-vicinity} +returns @code{#f}. @end defun -@deffn Procedure array-set! array new-value index1 index2 @dots{} -@end deffn +@c @defun scheme-file-suffix +@c Returns the default filename suffix for scheme source files. On most +@c systems this is @samp{.scm}.@refill +@c @end defun -@defun array-1d-ref array index -@defunx array-2d-ref array index index -@defunx array-3d-ref array index index index +@defun in-vicinity vicinity filename +Returns a filename suitable for use by @code{slib:load}, +@code{slib:load-source}, @code{slib:load-compiled}, +@code{open-input-file}, @code{open-output-file}, etc. The returned +filename is @var{filename} in @var{vicinity}. @code{in-vicinity} should +allow @var{filename} to override @var{vicinity} when @var{filename} is +an absolute pathname and @var{vicinity} is equal to the value of +@code{(user-vicinity)}. The behavior of @code{in-vicinity} when +@var{filename} is absolute and @var{vicinity} is not equal to the value +of @code{(user-vicinity)} is unspecified. For most systems +@code{in-vicinity} can be @code{string-append}.@refill @end defun -@deffn Procedure array-1d-set! array new-value index -@deffnx Procedure array-2d-set! array new-value index index -@deffnx Procedure array-3d-set! array new-value index index index -@end deffn +@defun sub-vicinity vicinity name +Returns the vicinity of @var{vicinity} restricted to @var{name}. This +is used for large systems where names of files in subsystems could +conflict. On systems with directory structure @code{sub-vicinity} will +return a pathname of the subdirectory @var{name} of +@var{vicinity}.@refill +@end defun -The functions are just fast versions of @code{array-ref} and -@code{array-set!} that take a fixed number of arguments, and perform no -bounds checking.@refill -If you comment out the bounds checking code, this is about as efficient -as you could ask for without help from the compiler. -An exercise left to the reader: implement the rest of APL. +@node Configuration, Input/Output, Vicinity, Built-in Support +@subsection Configuration +@noindent +These constants and procedures describe characteristics of the Scheme +and underlying operating system. They are provided by all +implementations. +@defvr Constant char-code-limit +An integer 1 larger that the largest value which can be returned by +@code{char->integer}.@refill +@end defvr -@node Array Mapping, Association Lists, Arrays, Data Structures -@section Array Mapping +@defvr Constant most-positive-fixnum +The immediate integer closest to positive infinity. +@end defvr -@code{(require 'array-for-each)} +@defvr Constant slib:tab +The tab character. +@end defvr -@defun array-map! array0 proc array1 @dots{} -@var{array1}, @dots{} must have the same number of dimensions as -@var{array0} and have a range for each index which includes the range -for the corresponding index in @var{array0}. @var{proc} is applied to -each tuple of elements of @var{array1} @dots{} and the result is stored -as the corresponding element in @var{array0}. The value returned is -unspecified. The order of application is unspecified. -@end defun +@defvr Constant slib:form-feed +The form-feed character. +@end defvr -@defun array-for-each @var{proc} @var{array0} @dots{} -@var{proc} is applied to each tuple of elements of @var{array0} @dots{} -in row-major order. The value returned is unspecified. +@defun software-type +Returns a symbol denoting the generic operating system type. For +instance, @code{unix}, @code{vms}, @code{macos}, @code{amiga}, or +@code{ms-dos}. @end defun -@defun array-indexes @var{array} -Returns an array of lists of indexes for @var{array} such that, if -@var{li} is a list of indexes for which @var{array} is defined, (equal? -@var{li} (apply array-ref (array-indexes @var{array}) @var{li})). -@end defun +@defun slib:report-version +Displays the versions of SLIB and the underlying Scheme implementation +and the name of the operating system. An unspecified value is returned. -@defun array-copy! source destination -Copies every element from vector or array @var{source} to the -corresponding element of @var{destination}. @var{destination} must have -the same rank as @var{source}, and be at least as large in each -dimension. The order of copying is unspecified. +@example +(slib:report-version) @result{} slib "2c0" on scm "5b1" on unix +@end example @end defun +@defun slib:report +Displays the information of @code{(slib:report-version)} followed by +almost all the information neccessary for submitting a problem report. +An unspecified value is returned. -@node Association Lists, Collections, Array Mapping, Data Structures -@section Association Lists +@defunx slib:report #t +provides a more verbose listing. -@code{(require 'alist)} +@defunx slib:report filename +Writes the report to file @file{filename}. -Alist functions provide utilities for treating a list of key-value pairs -as an associative database. These functions take an equality predicate, -@var{pred}, as an argument. This predicate should be repeatable, -symmetric, and transitive.@refill +@example +(slib:report) +@result{} +slib "2c0" on scm "5b1" on unix +(implementation-vicinity) is "/home/jaffer/scm/" +(library-vicinity) is "/home/jaffer/slib/" +(scheme-file-suffix) is ".scm" +loaded *features* : + trace alist qp sort + common-list-functions macro values getopt + compiled +implementation *features* : + bignum complex real rational + inexact vicinity ed getenv + tmpnam abort transcript with-file + ieee-p1178 rev4-report rev4-optional-procedures hash + object-hash delay eval dynamic-wind + multiarg-apply multiarg/and- logical defmacro + string-port source current-time record + rev3-procedures rev2-procedures sun-dl string-case + array dump char-ready? full-continuation + system +implementation *catalog* : + (i/o-extensions compiled "/home/jaffer/scm/ioext.so") + ... +@end example +@end defun -Alist functions can be used with a secondary index method such as hash -tables for improved performance. +@node Input/Output, Legacy, Configuration, Built-in Support +@subsection Input/Output -@defun predicate->asso pred -Returns an @dfn{association function} (like @code{assq}, @code{assv}, or -@code{assoc}) corresponding to @var{pred}. The returned function -returns a key-value pair whose key is @code{pred}-equal to its first -argument or @code{#f} if no key in the alist is @var{pred}-equal to the -first argument.@refill -@end defun +@noindent +These procedures are provided by all implementations. -@defun alist-inquirer pred -Returns a procedure of 2 arguments, @var{alist} and @var{key}, which -returns the value associated with @var{key} in @var{alist} or @code{#f} if -@var{key} does not appear in @var{alist}.@refill -@end defun +@deffn Procedure file-exists? filename +Returns @code{#t} if the specified file exists. Otherwise, returns +@code{#f}. If the underlying implementation does not support this +feature then @code{#f} is always returned. +@end deffn -@defun alist-associator pred -Returns a procedure of 3 arguments, @var{alist}, @var{key}, and -@var{value}, which returns an alist with @var{key} and @var{value} -associated. Any previous value associated with @var{key} will be -lost. This returned procedure may or may not have side effects on its -@var{alist} argument. An example of correct usage is:@refill +@deffn Procedure delete-file filename +Deletes the file specified by @var{filename}. If @var{filename} can not +be deleted, @code{#f} is returned. Otherwise, @code{#t} is +returned.@refill +@end deffn + +@deffn Procedure tmpnam +Returns a pathname for a file which will likely not be used by any other +process. Successive calls to @code{(tmpnam)} will return different +pathnames.@refill +@end deffn + +@deffn Procedure current-error-port +Returns the current port to which diagnostic and error output is +directed. +@end deffn + +@deffn Procedure force-output +@deffnx Procedure force-output port +Forces any pending output on @var{port} to be delivered to the output +device and returns an unspecified value. The @var{port} argument may be +omitted, in which case it defaults to the value returned by +@code{(current-output-port)}.@refill +@end deffn + +@deffn Procedure output-port-width +@deffnx Procedure output-port-width port + +Returns the width of @var{port}, which defaults to +@code{(current-output-port)} if absent. If the width cannot be +determined 79 is returned.@refill +@end deffn + +@deffn Procedure output-port-height +@deffnx Procedure output-port-height port + +Returns the height of @var{port}, which defaults to +@code{(current-output-port)} if absent. If the height cannot be +determined 24 is returned.@refill +@end deffn + +@node Legacy, System, Input/Output, Built-in Support +@subsection Legacy + +These procedures are provided by all implementations. + +@defun identity x +@var{identity} returns its argument. + +Example: @lisp -(define put (alist-associator string-ci=?)) -(define alist '()) -(set! alist (put alist "Foo" 9)) +(identity 3) + @result{} 3 +(identity '(foo bar)) + @result{} (foo bar) +(map identity @var{lst}) + @equiv{} (copy-list @var{lst}) @end lisp @end defun -@defun alist-remover pred -Returns a procedure of 2 arguments, @var{alist} and @var{key}, which -returns an alist with an association whose @var{key} is key removed. -This returned procedure may or may not have side effects on its -@var{alist} argument. An example of correct usage is:@refill +@noindent +The following procedures were present in Scheme until R4RS +(@pxref{Notes, , Language changes ,r4rs, Revised(4) Scheme}). +They are provided by all SLIB implementations. + +@defvr Constant t +Derfined as @code{#t}. +@end defvr + +@defvr Constant nil +Defined as @code{#f}. +@end defvr + +@defun last-pair l +Returns the last pair in the list @var{l}. Example: @lisp -(define rem (alist-remover string-ci=?)) -(set! alist (rem alist "foo")) +(last-pair (cons 1 2)) + @result{} (1 . 2) +(last-pair '(1 2)) + @result{} (2) + @equiv{} (cons 2 '()) @end lisp @end defun -@defun alist-map proc alist -Returns a new association list formed by mapping @var{proc} over the -keys and values of @var{alist}. @var{proc} must be a function of 2 -arguments which returns the new value part. -@end defun +@node System, , Legacy, Built-in Support +@subsection System -@defun alist-for-each proc alist -Applies @var{proc} to each pair of keys and values of @var{alist}. -@var{proc} must be a function of 2 arguments. The returned value is -unspecified. -@end defun +@noindent +These procedures are provided by all implementations. +@deffn Procedure slib:load-source name +Loads a file of Scheme source code from @var{name} with the default +filename extension used in SLIB. For instance if the filename extension +used in SLIB is @file{.scm} then @code{(slib:load-source "foo")} will +load from file @file{foo.scm}. +@end deffn -@node Collections, Dynamic Data Type, Association Lists, Data Structures -@section Collections +@deffn Procedure slib:load-compiled name +On implementations which support separtely loadable compiled modules, +loads a file of compiled code from @var{name} with the implementation's +filename extension for compiled code appended. +@end deffn -@c Much of the documentation in this section was written by Dave Love -@c (d.love@dl.ac.uk) -- don't blame Ken Dickey for its faults. -@c but we can blame him for not writing it! +@deffn Procedure slib:load name +Loads a file of Scheme source or compiled code from @var{name} with the +appropriate suffixes appended. If both source and compiled code are +present with the appropriate names then the implementation will load +just one. It is up to the implementation to choose which one will be +loaded. -@code{(require 'collect)} +If an implementation does not support compiled code then +@code{slib:load} will be identical to @code{slib:load-source}. +@end deffn -Routines for managing collections. Collections are aggregate data -structures supporting iteration over their elements, similar to the -Dylan(TM) language, but with a different interface. They have -@dfn{elements} indexed by corresponding @dfn{keys}, although the keys -may be implicit (as with lists).@refill +@deffn Procedure slib:eval obj +@code{eval} returns the value of @var{obj} evaluated in the current top +level environment.@refill +@end deffn -New types of collections may be defined as YASOS objects (@xref{Yasos}). -They must support the following operations: -@itemize @bullet -@item -@code{(collection? @var{self})} (always returns @code{#t}); +@deffn Procedure slib:eval-load filename eval +@var{filename} should be a string. If filename names an existing file, +the Scheme source code expressions and definitions are read from the +file and @var{eval} called with them sequentially. The +@code{slib:eval-load} procedure does not affect the values returned by +@code{current-input-port} and @code{current-output-port}.@refill +@end deffn -@item -@code{(size @var{self})} returns the number of elements in the collection; +@deffn Procedure slib:warn arg1 arg2 @dots{} +Outputs a warning message containing the arguments. +@end deffn -@item -@code{(print @var{self} @var{port})} is a specialized print operation -for the collection which prints a suitable representation on the given -@var{port} or returns it as a string if @var{port} is @code{#t};@refill +@deffn Procedure slib:error arg1 arg2 @dots{} +Outputs an error message containing the arguments, aborts evaluation of +the current form and responds in a system dependent way to the error. +Typical responses are to abort the program or to enter a read-eval-print +loop.@refill +@end deffn + +@deffn Procedure slib:exit n +@deffnx Procedure slib:exit +Exits from the Scheme session returning status @var{n} to the system. +If @var{n} is omitted or @code{#t}, a success status is returned to the +system (if possible). If @var{n} is @code{#f} a failure is returned to +the system (if possible). If @var{n} is an integer, then @var{n} is +returned to the system (if possible). If the Scheme session cannot exit +an unspecified value is returned from @code{slib:exit}. +@end deffn + +@node About this manual, , Built-in Support, The Library System +@section About this manual + +@itemize @bullet @item -@code{(gen-elts @var{self})} returns a thunk which on successive -invocations yields elements of @var{self} in order or gives an error if -it is invoked more than @code{(size @var{self})} times;@refill +Entries that are labeled as Functions are called for their return +values. Entries that are labeled as Procedures are called primarily for +their side effects. @item -@code{(gen-keys @var{self})} is like @code{gen-elts}, but yields the -collection's keys in order. +Examples in this text were produced using the @code{scm} Scheme +implementation. +@item +At the beginning of each section, there is a line that looks like +@ftindex feature +@code{(require 'feature)}. Include this line in your code prior to +using the package. @end itemize -They might support specialized @code{for-each-key} and -@code{for-each-elt} operations.@refill -@defun collection? obj -A predicate, true initially of lists, vectors and strings. New sorts of -collections must answer @code{#t} to @code{collection?}.@refill -@end defun -@deffn Procedure map-elts proc . collections -@deffnx Procedure do-elts proc . collections -@var{proc} is a procedure taking as many arguments as there are -@var{collections} (at least one). The @var{collections} are iterated -over in their natural order and @var{proc} is applied to the elements -yielded by each iteration in turn. The order in which the arguments are -supplied corresponds to te order in which the @var{collections} appear. -@code{do-elts} is used when only side-effects of @var{proc} are of -interest and its return value is unspecified. @code{map-elts} returns a -collection (actually a vector) of the results of the applications of -@var{proc}.@refill +@node Scheme Syntax Extension Packages, Textual Conversion Packages, The Library System, Top +@chapter Scheme Syntax Extension Packages -Example: -@lisp -(map-elts + (list 1 2 3) (vector 1 2 3)) - @result{} #(2 4 6) -@end lisp -@end deffn +@menu +* Defmacro:: Supported by all implementations -@deffn Procedure map-keys proc . collections -@deffnx Procedure do-keys proc . collections -These are analogous to @code{map-elts} and @code{do-elts}, but each -iteration is over the @var{collections}' @emph{keys} rather than their -elements.@refill +* R4RS Macros:: 'macro +* Macro by Example:: 'macro-by-example +* Macros That Work:: 'macros-that-work +* Syntactic Closures:: 'syntactic-closures +* Syntax-Case Macros:: 'syntax-case -Example: -@lisp -(map-keys + (list 1 2 3) (vector 1 2 3)) - @result{} #(0 2 4) -@end lisp -@end deffn +Syntax extensions (macros) included with SLIB. Also @xref{Structures}. -@deffn Procedure for-each-key collection proc -@deffnx Procedure for-each-elt collection proc -These are like @code{do-keys} and @code{do-elts} but only for a single -collection; they are potentially more efficient. -@end deffn +* Fluid-Let:: 'fluid-let +* Yasos:: 'yasos, 'oop, 'collect +@end menu -@defun reduce proc seed . collections -A generalization of the list-based @code{comlist:reduce-init} -(@xref{Lists as sequences}) to collections which will shadow the -list-based version if @code{(require 'collect)} follows @code{(require -'common-list-functions)} (@xref{Common List Functions}).@refill -Examples: +@node Defmacro, R4RS Macros, Scheme Syntax Extension Packages, Scheme Syntax Extension Packages +@section Defmacro + +Defmacros are supported by all implementations. +@c See also @code{gentemp}, in @ref{Macros}. + +@defun gentemp +Returns a new (interned) symbol each time it is called. The symbol +names are implementation-dependent @lisp -(reduce + 0 (vector 1 2 3)) - @result{} 6 -(reduce union '() '((a b c) (b c d) (d a))) - @result{} (c b d a). +(gentemp) @result{} scm:G0 +(gentemp) @result{} scm:G1 @end lisp @end defun -@defun any? pred . collections -A generalization of the list-based @code{some} (@xref{Lists as -sequences}) to collections.@refill +@defun defmacro:eval e +Returns the @code{slib:eval} of expanding all defmacros in scheme +expression @var{e}. +@end defun -Example: -@lisp -(any? odd? (list 2 3 4 5)) - @result{} #t -@end lisp +@defun defmacro:load filename +@var{filename} should be a string. If filename names an existing file, +the @code{defmacro:load} procedure reads Scheme source code expressions +and definitions from the file and evaluates them sequentially. These +source code expressions and definitions may contain defmacro +definitions. The @code{macro:load} procedure does not affect the values +returned by @code{current-input-port} and +@code{current-output-port}.@refill @end defun -@defun every? pred . collections -A generalization of the list-based @code{every} (@xref{Lists as -sequences}) to collections.@refill +@defun defmacro? sym +Returns @code{#t} if @var{sym} has been defined by @code{defmacro}, +@code{#f} otherwise. +@end defun -Example: -@lisp -(every? collection? '((1 2) #(1 2))) - @result{} #t -@end lisp +@defun macroexpand-1 form +@defunx macroexpand form +If @var{form} is a macro call, @code{macroexpand-1} will expand the +macro call once and return it. A @var{form} is considered to be a macro +call only if it is a cons whose @code{car} is a symbol for which a +@code{defmacr} has been defined. + +@code{macroexpand} is similar to @code{macroexpand-1}, but repeatedly +expands @var{form} until it is no longer a macro call. @end defun -@defun empty? collection -Returns @code{#t} iff there are no elements in @var{collection}. +@defmac defmacro name lambda-list form @dots{} +When encountered by @code{defmacro:eval}, @code{defmacro:macroexpand*}, +or @code{defmacro:load} defines a new macro which will henceforth be +expanded when encountered by @code{defmacro:eval}, +@code{defmacro:macroexpand*}, or @code{defmacro:load}. +@end defmac -@code{(empty? @var{collection}) @equiv{} (zero? (size @var{collection}))} +@subsection Defmacroexpand +@code{(require 'defmacroexpand)} +@ftindex defmacroexpand + +@defun defmacro:expand* e +Returns the result of expanding all defmacros in scheme expression +@var{e}. @end defun -@defun size collection -Returns the number of elements in @var{collection}. +@node R4RS Macros, Macro by Example, Defmacro, Scheme Syntax Extension Packages +@section R4RS Macros + +@code{(require 'macro)} is the appropriate call if you want R4RS +@ftindex macro +high-level macros but don't care about the low level implementation. If +an SLIB R4RS macro implementation is already loaded it will be used. +Otherwise, one of the R4RS macros implemetations is loaded. + +The SLIB R4RS macro implementations support the following uniform +interface: + +@defun macro:expand sexpression +Takes an R4RS expression, macro-expands it, and returns the result of +the macro expansion. @end defun -@defun Setter list-ref -See @xref{Setters} for a definition of @dfn{setter}. N.B. -@code{(setter list-ref)} doesn't work properly for element 0 of a -list.@refill +@defun macro:eval sexpression +Takes an R4RS expression, macro-expands it, evals the result of the +macro expansion, and returns the result of the evaluation. @end defun -Here is a sample collection: @code{simple-table} which is also a -@code{table}.@refill -@lisp -(define-predicate TABLE?) -(define-operation (LOOKUP table key failure-object)) -(define-operation (ASSOCIATE! table key value)) ;; returns key -(define-operation (REMOVE! table key)) ;; returns value +@deffn Procedure macro:load filename +@var{filename} should be a string. If filename names an existing file, +the @code{macro:load} procedure reads Scheme source code expressions and +definitions from the file and evaluates them sequentially. These source +code expressions and definitions may contain macro definitions. The +@code{macro:load} procedure does not affect the values returned by +@code{current-input-port} and @code{current-output-port}.@refill +@end deffn -(define (MAKE-SIMPLE-TABLE) - (let ( (table (list)) ) - (object - ;; table behaviors - ((TABLE? self) #t) - ((SIZE self) (size table)) - ((PRINT self port) (format port "#")) - ((LOOKUP self key failure-object) - (cond - ((assq key table) => cdr) - (else failure-object) - )) - ((ASSOCIATE! self key value) - (cond - ((assq key table) - => (lambda (bucket) (set-cdr! bucket value) key)) - (else - (set! table (cons (cons key value) table)) - key) - )) - ((REMOVE! self key);; returns old value - (cond - ((null? table) (slib:error "TABLE:REMOVE! Key not found: " key)) - ((eq? key (caar table)) - (let ( (value (cdar table)) ) - (set! table (cdr table)) - value) - ) - (else - (let loop ( (last table) (this (cdr table)) ) - (cond - ((null? this) - (slib:error "TABLE:REMOVE! Key not found: " key)) - ((eq? key (caar this)) - (let ( (value (cdar this)) ) - (set-cdr! last (cdr this)) - value) - ) - (else - (loop (cdr last) (cdr this))) - ) ) ) - )) - ;; collection behaviors - ((COLLECTION? self) #t) - ((GEN-KEYS self) (collect:list-gen-elts (map car table))) - ((GEN-ELTS self) (collect:list-gen-elts (map cdr table))) - ((FOR-EACH-KEY self proc) - (for-each (lambda (bucket) (proc (car bucket))) table) - ) - ((FOR-EACH-ELT self proc) - (for-each (lambda (bucket) (proc (cdr bucket))) table) - ) - ) ) ) -@end lisp +@node Macro by Example, Macros That Work, R4RS Macros, Scheme Syntax Extension Packages +@section Macro by Example +@code{(require 'macro-by-example)} +@ftindex macro-by-example +A vanilla implementation of @cite{Macro by Example} (Eugene Kohlbecker, +R4RS) by Dorai Sitaram, (dorai@@cs.rice.edu) using @code{defmacro}. +@itemize @bullet +@item +generating hygienic global @code{define-syntax} Macro-by-Example macros +@strong{cheaply}. -@node Dynamic Data Type, Hash Tables, Collections, Data Structures -@section Dynamic Data Type +@item +can define macros which use @code{...}. -@code{(require 'dynamic)} +@item +needn't worry about a lexical variable in a macro definition +clashing with a variable from the macro use context -@defun make-dynamic obj -Create and returns a new @dfn{dynamic} whose global value is @var{obj}. -@end defun +@item +don't suffer the overhead of redefining the repl if @code{defmacro} +natively supported (most implementations) -@defun dynamic? obj -Returns true if and only if @var{obj} is a dynamic. No object -satisfying @code{dynamic?} satisfies any of the other standard type -predicates.@refill -@end defun +@end itemize +@subsection Caveat +These macros are not referentially transparent (@pxref{Macros, , ,r4rs, +Revised(4) Scheme}). Lexically scoped macros (i.e., @code{let-syntax} +and @code{letrec-syntax}) are not supported. In any case, the problem +of referential transparency gains poignancy only when @code{let-syntax} +and @code{letrec-syntax} are used. So you will not be courting +large-scale disaster unless you're using system-function names as local +variables with unintuitive bindings that the macro can't use. However, +if you must have the full @cite{r4rs} macro functionality, look to the +more featureful (but also more expensive) versions of syntax-rules +available in slib @ref{Macros That Work}, @ref{Syntactic Closures}, and +@ref{Syntax-Case Macros}. -@defun dynamic-ref dyn -Return the value of the given dynamic in the current dynamic -environment. -@end defun +@defmac define-syntax keyword transformer-spec +The @var{keyword} is an identifier, and the @var{transformer-spec} +should be an instance of @code{syntax-rules}. -@deffn Procedure dynamic-set! dyn obj -Change the value of the given dynamic to @var{obj} in the current -dynamic environment. The returned value is unspecified.@refill -@end deffn +The top-level syntactic environment is extended by binding the +@var{keyword} to the specified transformer. -@defun call-with-dynamic-binding dyn obj thunk -Invoke and return the value of the given thunk in a new, nested dynamic -environment in which the given dynamic has been bound to a new location -whose initial contents are the value @var{obj}. This dynamic -environment has precisely the same extent as the invocation of the thunk -and is thus captured by continuations created within that invocation and -re-established by those continuations when they are invoked.@refill -@end defun +@example +(define-syntax let* + (syntax-rules () + ((let* () body1 body2 ...) + (let () body1 body2 ...)) + ((let* ((name1 val1) (name2 val2) ...) + body1 body2 ...) + (let ((name1 val1)) + (let* (( name2 val2) ...) + body1 body2 ...))))) +@end example +@end defmac -The @code{dynamic-bind} macro is not implemented. +@defmac syntax-rules literals syntax-rule @dots{} +@var{literals} is a list of identifiers, and each @var{syntax-rule} +should be of the form +@code{(@var{pattern} @var{template})} +where the @var{pattern} and @var{template} are as in the grammar above. +An instance of @code{syntax-rules} produces a new macro transformer by +specifying a sequence of hygienic rewrite rules. A use of a macro whose +keyword is associated with a transformer specified by +@code{syntax-rules} is matched against the patterns contained in the +@var{syntax-rule}s, beginning with the leftmost @var{syntax-rule}. +When a match is found, the macro use is trancribed hygienically +according to the template. -@node Hash Tables, Hashing, Dynamic Data Type, Data Structures -@section Hash Tables +Each pattern begins with the keyword for the macro. This keyword is not +involved in the matching and is not considered a pattern variable or +literal identifier. +@end defmac -@code{(require 'hash-table)} +@node Macros That Work, Syntactic Closures, Macro by Example, Scheme Syntax Extension Packages +@section Macros That Work -@defun predicate->hash pred -Returns a hash function (like @code{hashq}, @code{hashv}, or -@code{hash}) corresponding to the equality predicate @var{pred}. -@var{pred} should be @code{eq?}, @code{eqv?}, @code{equal?}, @code{=}, -@code{char=?}, @code{char-ci=?}, @code{string=?}, or -@code{string-ci=?}.@refill -@end defun +@code{(require 'macros-that-work)} +@ftindex macros-that-work -A hash table is a vector of association lists. +@cite{Macros That Work} differs from the other R4RS macro +implementations in that it does not expand derived expression types to +primitive expression types. -@defun make-hash-table k -Returns a vector of @var{k} empty (association) lists. +@defun macro:expand expression +@defunx macwork:expand expression +Takes an R4RS expression, macro-expands it, and returns the result of +the macro expansion. @end defun -Hash table functions provide utilities for an associative database. -These functions take an equality predicate, @var{pred}, as an argument. -@var{pred} should be @code{eq?}, @code{eqv?}, @code{equal?}, @code{=}, -@code{char=?}, @code{char-ci=?}, @code{string=?}, or -@code{string-ci=?}.@refill - -@defun predicate->hash-asso pred -Returns a hash association function of 2 arguments, @var{key} and -@var{hashtab}, corresponding to @var{pred}. The returned function -returns a key-value pair whose key is @var{pred}-equal to its first -argument or @code{#f} if no key in @var{hashtab} is @var{pred}-equal to -the first argument.@refill -@end defun - -@defun hash-inquirer pred -Returns a procedure of 3 arguments, @code{hashtab} and @code{key}, which -returns the value associated with @code{key} in @code{hashtab} or -@code{#f} if key does not appear in @code{hashtab}.@refill +@defun macro:eval expression +@defunx macwork:eval expression +@code{macro:eval} returns the value of @var{expression} in the current +top level environment. @var{expression} can contain macro definitions. +Side effects of @var{expression} will affect the top level +environment.@refill @end defun -@defun hash-associator pred -Returns a procedure of 3 arguments, @var{hashtab}, @var{key}, and -@var{value}, which modifies @var{hashtab} so that @var{key} and -@var{value} associated. Any previous value associated with @var{key} -will be lost.@refill -@end defun +@deffn Procedure macro:load filename +@deffnx Procedure macwork:load filename +@var{filename} should be a string. If filename names an existing file, +the @code{macro:load} procedure reads Scheme source code expressions and +definitions from the file and evaluates them sequentially. These source +code expressions and definitions may contain macro definitions. The +@code{macro:load} procedure does not affect the values returned by +@code{current-input-port} and @code{current-output-port}.@refill +@end deffn -@defun hash-remover pred -Returns a procedure of 2 arguments, @var{hashtab} and @var{key}, which -modifies @var{hashtab} so that the association whose key is @var{key} is -removed.@refill -@end defun +References: -@defun hash-map proc hash-table -Returns a new hash table formed by mapping @var{proc} over the -keys and values of @var{hash-table}. @var{proc} must be a function of 2 -arguments which returns the new value part. -@end defun +The @cite{Revised^4 Report on the Algorithmic Language Scheme} Clinger +and Rees [editors]. To appear in LISP Pointers. Also available as a +technical report from the University of Oregon, MIT AI Lab, and +Cornell.@refill -@defun hash-for-each proc hash-table -Applies @var{proc} to each pair of keys and values of @var{hash-table}. -@var{proc} must be a function of 2 arguments. The returned value is -unspecified. -@end defun +@center Macros That Work. Clinger and Rees. POPL '91. +The supported syntax differs from the R4RS in that vectors are allowed +as patterns and as templates and are not allowed as pattern or template +data. +@example +transformer spec @expansion{} (syntax-rules literals rules) +rules @expansion{} () + | (rule . rules) +rule @expansion{} (pattern template) -@node Hashing, Chapter Ordering, Hash Tables, Data Structures -@section Hashing +pattern @expansion{} pattern_var ; a symbol not in literals + | symbol ; a symbol in literals + | () + | (pattern . pattern) + | (ellipsis_pattern) + | #(pattern*) ; extends R4RS + | #(pattern* ellipsis_pattern) ; extends R4RS + | pattern_datum -@code{(require 'hash)} +template @expansion{} pattern_var + | symbol + | () + | (template2 . template2) + | #(template*) ; extends R4RS + | pattern_datum -These hashing functions are for use in quickly classifying objects. -Hash tables use these functions. +template2 @expansion{} template + | ellipsis_template -@defun hashq obj k -@defunx hashv obj k -@defunx hash obj k -Returns an exact non-negative integer less than @var{k}. For each -non-negative integer less than @var{k} there are arguments @var{obj} for -which the hashing functions applied to @var{obj} and @var{k} returns -that integer.@refill +pattern_datum @expansion{} string ; no vector + | character + | boolean + | number -For @code{hashq}, @code{(eq? obj1 obj2)} implies @code{(= (hashq obj1 k) -(hashq obj2))}.@refill +ellipsis_pattern @expansion{} pattern ... -For @code{hashv}, @code{(eqv? obj1 obj2)} implies @code{(= (hashv obj1 k) -(hashv obj2))}.@refill +ellipsis_template @expansion{} template ... -For @code{hash}, @code{(equal? obj1 obj2)} implies @code{(= (hash obj1 k) -(hash obj2))}.@refill +pattern_var @expansion{} symbol ; not in literals -@code{hash}, @code{hashv}, and @code{hashq} return in time bounded by a -constant. Notice that items having the same @code{hash} implies the -items have the same @code{hashv} implies the items have the same -@code{hashq}.@refill -@end defun +literals @expansion{} () + | (symbol . literals) +@end example +@subsection Definitions -@code{(require 'sierpinski)} +@table @asis -@defun make-sierpinski-indexer max-coordinate -Returns a procedure (eg hash-function) of 2 numeric arguments which -preserves @emph{nearness} in its mapping from NxN to N. +@item Scope of an ellipsis +Within a pattern or template, the scope of an ellipsis (@code{...}) is +the pattern or template that appears to its left. -@var{max-coordinate} is the maximum coordinate (a positive integer) of a -population of points. The returned procedures is a function that takes -the x and y coordinates of a point, (non-negative integers) and returns -an integer corresponding to the relative position of that point along a -Sierpinski curve. (You can think of this as computing a (pseudo-) -inverse of the Sierpinski spacefilling curve.) +@item Rank of a pattern variable +The rank of a pattern variable is the number of ellipses within whose +scope it appears in the pattern. -Example use: Make an indexer (hash-function) for integer points lying in -square of integer grid points [0,99]x[0,99]: -@example -(define space-key (make-sierpinski-indexer 100)) -@end example -Now let's compute the index of some points: -@example -(space-key 24 78) @result{} 9206 -(space-key 23 80) @result{} 9172 -@end example +@item Rank of a subtemplate +The rank of a subtemplate is the number of ellipses within whose scope +it appears in the template. -Note that locations (24, 78) and (23, 80) are near in index and -therefore, because the Sierpinski spacefilling curve is continuous, we -know they must also be near in the plane. Nearness in the plane does -not, however, necessarily correspond to nearness in index, although it -@emph{tends} to be so. +@item Template rank of an occurrence of a pattern variable +The template rank of an occurrence of a pattern variable within a +template is the rank of that occurrence, viewed as a subtemplate. -Example applications: -@table @asis +@item Variables bound by a pattern +The variables bound by a pattern are the pattern variables that appear +within it. -@item -Sort points by Sierpinski index to get heuristic solution to -@emph{travelling salesman problem}. For details of performance, -see L. Platzman and J. Bartholdi, "Spacefilling curves and the -Euclidean travelling salesman problem", JACM 36(4):719--737 -(October 1989) and references therein. +@item Referenced variables of a subtemplate +The referenced variables of a subtemplate are the pattern variables that +appear within it. -@item -Use Sierpinski index as key by which to store 2-dimensional data -in a 1-dimensional data structure (such as a table). Then -locations that are near each other in 2-d space will tend to -be near each other in 1-d data structure; and locations that -are near in 1-d data structure will be near in 2-d space. This -can significantly speed retrieval from secondary storage because -contiguous regions in the plane will tend to correspond to -contiguous regions in secondary storage. (This is a standard -technique for managing CAD/CAM or geographic data.) +@item Variables opened by an ellipsis template +The variables opened by an ellipsis template are the referenced pattern +variables whose rank is greater than the rank of the ellipsis template. @end table -@end defun - +@subsection Restrictions -@code{(require 'soundex)} +No pattern variable appears more than once within a pattern. -@defun soundex name -Computes the @emph{soundex} hash of @var{name}. Returns a string of an -initial letter and up to three digits between 0 and 6. Soundex -supposedly has the property that names that sound similar in normal -English pronunciation tend to map to the same key. +For every occurrence of a pattern variable within a template, the +template rank of the occurrence must be greater than or equal to the +pattern variable's rank. -Soundex was a classic algorithm used for manual filing of personal -records before the advent of computers. It performs adequately for -English names but has trouble with other nationalities. +Every ellipsis template must open at least one variable. -See Knuth, Vol. 3 @cite{Sorting and searching}, pp 391--2 +For every ellipsis template, the variables opened by an ellipsis +template must all be bound to sequences of the same length. -To manage unusual inputs, @code{soundex} omits all non-alphabetic -characters. Consequently, in this implementation: +The compiled form of a @var{rule} is @example -(soundex ) @result{} "" -(soundex "") @result{} "" -@end example +rule @expansion{} (pattern template inserted) -Examples from Knuth: +pattern @expansion{} pattern_var + | symbol + | () + | (pattern . pattern) + | ellipsis_pattern + | #(pattern) + | pattern_datum -@example -(map soundex '("Euler" "Gauss" "Hilbert" "Knuth" - "Lloyd" "Lukasiewicz")) - @result{} ("E460" "G200" "H416" "K530" "L300" "L222") +template @expansion{} pattern_var + | symbol + | () + | (template2 . template2) + | #(pattern) + | pattern_datum -(map soundex '("Ellery" "Ghosh" "Heilbronn" "Kant" - "Ladd" "Lissajous")) - @result{} ("E460" "G200" "H416" "K530" "L300" "L222") -@end example +template2 @expansion{} template + | ellipsis_template -Some cases in which the algorithm fails (Knuth): +pattern_datum @expansion{} string + | character + | boolean + | number -@example -(map soundex '("Rogers" "Rodgers")) @result{} ("R262" "R326") +pattern_var @expansion{} #(V symbol rank) -(map soundex '("Sinclair" "St. Clair")) @result{} ("S524" "S324") +ellipsis_pattern @expansion{} #(E pattern pattern_vars) -(map soundex '("Tchebysheff" "Chebyshev")) @result{} ("T212" "C121") -@end example -@end defun +ellipsis_template @expansion{} #(E template pattern_vars) -@node Chapter Ordering, Object, Hashing, Data Structures -@section Chapter Ordering +inserted @expansion{} () + | (symbol . inserted) -@code{(require 'chapter-order)} +pattern_vars @expansion{} () + | (pattern_var . pattern_vars) -The @samp{chap:} functions deal with strings which are ordered like -chapter numbers (or letters) in a book. Each section of the string -consists of consecutive numeric or consecutive aphabetic characters of -like case. +rank @expansion{} exact non-negative integer +@end example -@defun chap:string? string1 string2 -@defunx chap:string<=? string1 string2 -@defunx chap:string>=? string1 string2 -Implement the corresponding chapter-order predicates. -@end defun - -@defun chap:next-string string -Returns the next string in the @emph{chapter order}. If @var{string} -has no alphabetic or numeric characters, -@code{(string-append @var{string} "0")} is returnd. The argument to -chap:next-string will always be @code{chap:string::( ) -@end lisp -Generic-methods +Additionally, the following procedures are added: @lisp - ::value @result{} ::value - ::set-value! @result{} ::set-value! - ::describe @result{} ::describe - ::help - ::invert - ::inverter? +make-syntactic-closure +capture-syntactic-environment +identifier? +identifier=? @end lisp -@subsubsection Number Documention -Inheritance -@lisp - ::() -@end lisp -Slots -@lisp - :: -@end lisp -Generic Methods -@lisp - ::value - ::set-value! -@end lisp +The description of the facility is divided into three parts. The first +part defines basic terminology. The second part describes how macro +transformers are defined. The third part describes the use of +@dfn{identifiers}, which extend the syntactic closure mechanism to be +compatible with @code{syntax-rules}.@refill -@subsubsection Inverter code -@example -(require 'object) - -(define value (make-generic-method (lambda (val) val))) -(define set-value! (make-generic-method)) -(define invert (make-generic-method - (lambda (val) - (if (number? val) - (/ 1 val) - (error "Method not supported:" val))))) -(define noop (make-generic-method)) -(define inverter? (make-generic-predicate)) -(define describe (make-generic-method)) -(define help (make-generic-method)) - -(define (make-number x) - (define self (make-object)) - (make-method! self value (lambda (this) x)) - (make-method! self set-value! - (lambda (this new-value) (set! x new-value))) - self) - -(define (make-description str) - (define self (make-object)) - (make-method! self describe (lambda (this) str)) - (make-method! self help (lambda (this) "Help not available")) - self) - -(define (make-inverter) - (define self (make-object - (make-number 1) - (make-description "A number which can be inverted"))) - (define (get-method self value)) - (make-method! self invert (lambda (self) (/ 1 ( self)))) - (make-predicate! self inverter?) - (unmake-method! self help) - (make-method! self help - (lambda (self) - (display "Inverter Methods:") (newline) - (display " (value inverter) ==> n") (newline))) - self) - -;;;; Try it out - -(define invert! (make-generic-method)) - -(define x (make-inverter)) - -(make-method! x invert! (lambda () (set-value! x (/ 1 (value x))))) - -(value x) @result{} 1 -(set-value! x 33) @result{} undefined -(invert! x) @result{} undefined -(value x) @result{} 1/33 - -(unmake-method! x invert!) @result{} undefined - -(invert! x) @error{} ERROR: Method not supported: x -@end example +@subsubsection Terminology -@node Parameter lists, Priority Queues, Object, Data Structures -@section Parameter lists +This section defines the concepts and data types used by the syntactic +closures facility. -@code{(require 'parameters)} +@itemize @bullet -@noindent -Arguments to procedures in scheme are distinguished from each other by -their position in the procedure call. This can be confusing when a -procedure takes many arguments, many of which are not often used. +@item @dfn{Forms} are the syntactic entities out of which programs are +recursively constructed. A form is any expression, any definition, any +syntactic keyword, or any syntactic closure. The variable name that +appears in a @code{set!} special form is also a form. Examples of +forms:@refill +@lisp +17 +#t +car +(+ x 4) +(lambda (x) x) +(define pi 3.14159) +if +define +@end lisp -@noindent -A @dfn{parameter-list} is a way of passing named information to a -procedure. Procedures are also defined to set unused parameters to -default values, check parameters, and combine parameter lists. +@item An @dfn{alias} is an alternate name for a given symbol. It can +appear anywhere in a form that the symbol could be used, and when quoted +it is replaced by the symbol; however, it does not satisfy the predicate +@code{symbol?}. Macro transformers rarely distinguish symbols from +aliases, referring to both as identifiers.@refill -@noindent -A @var{parameter} has the form @code{(@r{parameter-name} @r{value1} -@dots{})}. This format allows for more than one value per -parameter-name. +@item A @dfn{syntactic} environment maps identifiers to their +meanings. More precisely, it determines whether an identifier is a +syntactic keyword or a variable. If it is a keyword, the meaning is an +interpretation for the form in which that keyword appears. If it is a +variable, the meaning identifies which binding of that variable is +referenced. In short, syntactic environments contain all of the +contextual information necessary for interpreting the meaning of a +particular form.@refill -@noindent -A @var{parameter-list} is a list of @var{parameter}s, each with a -different @var{parameter-name}. +@item A @dfn{syntactic closure} consists of a form, a syntactic +environment, and a list of identifiers. All identifiers in the form +take their meaning from the syntactic environment, except those in the +given list. The identifiers in the list are to have their meanings +determined later. A syntactic closure may be used in any context in +which its form could have been used. Since a syntactic closure is also +a form, it may not be used in contexts where a form would be illegal. +For example, a form may not appear as a clause in the cond special form. +A syntactic closure appearing in a quoted structure is replaced by its +form.@refill -@deffn Function make-parameter-list parameter-names -Returns an empty parameter-list with slots for @var{parameter-names}. -@end deffn +@end itemize -@deffn Function parameter-list-ref parameter-list parameter-name -@var{parameter-name} must name a valid slot of @var{parameter-list}. -@code{parameter-list-ref} returns the value of parameter -@var{parameter-name} of @var{parameter-list}. -@end deffn +@subsubsection Transformer Definition -@deffn Procedure adjoin-parameters! parameter-list parameter1 @dots{} -Returns @var{parameter-list} with @var{parameter1} @dots{} merged in. -@end deffn +This section describes the @code{transformer} special form and the +procedures @code{make-syntactic-closure} and +@code{capture-syntactic-environment}.@refill -@deffn Procedure parameter-list-expand expanders parameter-list -@var{expanders} is a list of procedures whose order matches the order of -the @var{parameter-name}s in the call to @code{make-parameter-list} -which created @var{parameter-list}. For each non-false element of -@var{expanders} that procedure is mapped over the corresponding -parameter value and the returned parameter lists are merged into -@var{parameter-list}. +@deffn Syntax transformer expression -This process is repeated until @var{parameter-list} stops growing. The -value returned from @code{parameter-list-expand} is unspecified. -@end deffn +Syntax: It is an error if this syntax occurs except as a +@var{transformer spec}.@refill -@deffn Function fill-empty-parameters defaults parameter-list -@var{defaults} is a list of lists whose order matches the order of the -@var{parameter-name}s in the call to @code{make-parameter-list} which -created @var{parameter-list}. @code{fill-empty-parameters} returns a -new parameter-list with each empty parameter filled with the -corresponding @var{default}. -@end deffn +Semantics: The @var{expression} is evaluated in the standard transformer +environment to yield a macro transformer as described below. This macro +transformer is bound to a macro keyword by the special form in which the +@code{transformer} expression appears (for example, +@code{let-syntax}).@refill -@deffn Function check-parameters checks parameter-list -@var{checks} is a list of procedures whose order matches the order of -the @var{parameter-name}s in the call to @code{make-parameter-list} -which created @var{parameter-list}. +A @dfn{macro transformer} is a procedure that takes two arguments, a +form and a syntactic environment, and returns a new form. The first +argument, the @dfn{input form}, is the form in which the macro keyword +occurred. The second argument, the @dfn{usage environment}, is the +syntactic environment in which the input form occurred. The result of +the transformer, the @dfn{output form}, is automatically closed in the +@dfn{transformer environment}, which is the syntactic environment in +which the @code{transformer} expression occurred.@refill -@code{check-parameters} returns @var{parameter-list} if each @var{check} -of the corresponding @var{parameter-list} returns non-false. If some -@var{check} returns @code{#f} an error is signaled. -@end deffn +For example, here is a definition of a push macro using +@code{syntax-rules}:@refill +@lisp +(define-syntax push + (syntax-rules () + ((push item list) + (set! list (cons item list))))) +@end lisp -@noindent -In the following procedures @var{arities} is a list of symbols. The -elements of @code{arities} can be: +Here is an equivalent definition using @code{transformer}: +@lisp +(define-syntax push + (transformer + (lambda (exp env) + (let ((item + (make-syntactic-closure env '() (cadr exp))) + (list + (make-syntactic-closure env '() (caddr exp)))) + `(set! ,list (cons ,item ,list)))))) +@end lisp -@table @code -@item single -Requires a single parameter. -@item optional -A single parameter or no parameter is acceptable. -@item boolean -A single boolean parameter or zero parameters is acceptable. -@item nary -Any number of parameters are acceptable. -@item nary1 -One or more of parameters are acceptable. -@end table +In this example, the identifiers @code{set!} and @code{cons} are closed +in the transformer environment, and thus will not be affected by the +meanings of those identifiers in the usage environment +@code{env}.@refill -@deffn Function parameter-list->arglist positions arities types parameter-list -Returns @var{parameter-list} converted to an argument list. Parameters -of @var{arity} type @code{single} and @code{boolean} are converted to -the single value associated with them. The other @var{arity} types are -converted to lists of the value(s) of type @var{types}. - -@var{positions} is a list of positive integers whose order matches the -order of the @var{parameter-name}s in the call to -@code{make-parameter-list} which created @var{parameter-list}. The -integers specify in which argument position the corresponding parameter -should appear. -@end deffn - -@deffn Function getopt->parameter-list argc argv optnames arities types aliases -Returns @var{argv} converted to a parameter-list. @var{optnames} are -the parameter-names. @var{aliases} is a list of lists of strings and -elements of @var{optnames}. Each of these strings which have length of -1 will be treated as a single @key{-} option by @code{getopt}. Longer -strings will be treated as long-named options (@pxref{Getopt, getopt--}). -@end deffn +Some macros may be non-hygienic by design. For example, the following +defines a loop macro that implicitly binds @code{exit} to an escape +procedure. The binding of @code{exit} is intended to capture free +references to @code{exit} in the body of the loop, so @code{exit} must +be left free when the body is closed:@refill +@lisp +(define-syntax loop + (transformer + (lambda (exp env) + (let ((body (cdr exp))) + `(call-with-current-continuation + (lambda (exit) + (let f () + ,@@(map (lambda (exp) + (make-syntactic-closure env '(exit) + exp)) + body) + (f)))))))) +@end lisp -@deffn Function getopt->arglist argc argv optnames positions arities types defaults checks aliases -Like @code{getopt->parameter-list}, but converts @var{argv} to an -argument-list as specified by @var{optnames}, @var{positions}, -@var{arities}, @var{types}, @var{defaults}, @var{checks}, and -@var{aliases}. +To assign meanings to the identifiers in a form, use +@code{make-syntactic-closure} to close the form in a syntactic +environment.@refill @end deffn -These @code{getopt} functions can be used with SLIB relational -databases. For an example, @xref{Database Utilities, -make-command-server}. +@defun make-syntactic-closure environment free-names form -@node Priority Queues, Queues, Parameter lists, Data Structures -@section Priority Queues +@var{environment} must be a syntactic environment, @var{free-names} must +be a list of identifiers, and @var{form} must be a form. +@code{make-syntactic-closure} constructs and returns a syntactic closure +of @var{form} in @var{environment}, which can be used anywhere that +@var{form} could have been used. All the identifiers used in +@var{form}, except those explicitly excepted by @var{free-names}, obtain +their meanings from @var{environment}.@refill -@code{(require 'priority-queue)} +Here is an example where @var{free-names} is something other than the +empty list. It is instructive to compare the use of @var{free-names} in +this example with its use in the @code{loop} example above: the examples +are similar except for the source of the identifier being left +free.@refill +@lisp +(define-syntax let1 + (transformer + (lambda (exp env) + (let ((id (cadr exp)) + (init (caddr exp)) + (exp (cadddr exp))) + `((lambda (,id) + ,(make-syntactic-closure env (list id) exp)) + ,(make-syntactic-closure env '() init)))))) +@end lisp -@defun make-heap pred to make it compatible with, and easily usable +with, SLIB. Mainly, these adaptations consisted of: -@defun record-type-descriptor record -Returns a record-type descriptor representing the type of the given -record. That is, for example, if the returned descriptor were passed to -@code{record-predicate}, the resulting predicate would return a true -value when passed the given record. Note that it is not necessarily the -case that the returned descriptor is the one that was passed to -@code{record-constructor} in the call that created the constructor -procedure that created the given record.@refill -@end defun +@itemize @bullet +@item +Removing white space from @file{expand.pp} to save space in the +distribution. This file is not meant for human readers anyway@dots{} -@defun record-type-name rtd -Returns the type-name associated with the type represented by rtd. The -returned value is @code{eqv?} to the @var{type-name} argument given in -the call to @code{make-record-type} that created the type represented by -@var{rtd}.@refill -@end defun +@item +Removed a couple of Chez scheme dependencies. -@defun record-type-field-names rtd -Returns a list of the symbols naming the fields in members of the type -represented by @var{rtd}. The returned value is @code{equal?} to the -field-names argument given in the call to @code{make-record-type} that -created the type represented by @var{rtd}.@refill -@end defun +@item +Renamed global variables used to minimize the possibility of name +conflicts. +@item +Adding an SLIB-specific initialization file. +@item +Removing a couple extra files, most notably the documentation (but see +below). +@end itemize -@node Base Table, Relational Database, Records, Data Structures -@section Base Table +If you wish, you can see exactly what changes were done by reading the +shell script in the file @file{syncase.sh}. -A base table implementation using Scheme association lists is available -as the value of the identifier @code{alist-table} after doing: +The two PostScript files were omitted in order to not burden the SLIB +distribution with them. If you do intend to use @code{syntax-case}, +however, you should get these files and print them out on a PostScript +printer. They are available with the original @code{syntax-case} +distribution by anonymous FTP in +@file{cs.indiana.edu:/pub/scheme/syntax-case}.@refill -@example -(require 'alist-table) -@end example +In order to use syntax-case from an interactive top level, execute: +@lisp +(require 'syntax-case) +@ftindex syntax-case +(require 'repl) +@ftindex repl +(repl:top-level macro:eval) +@end lisp +See the section Repl (@xref{Repl}) for more information. +To check operation of syntax-case get +@file{cs.indiana.edu:/pub/scheme/syntax-case}, and type +@lisp +(require 'syntax-case) +@ftindex syntax-case +(syncase:sanity-check) +@end lisp -Association list base tables are suitable for small databases and -support all Scheme types when temporary and readable/writeable Scheme -types when saved. I hope support for other base table implementations -will be added in the future. +Beware that @code{syntax-case} takes a long time to load -- about 20s on +a SPARCstation SLC (with SCM) and about 90s on a Macintosh SE/30 (with +Gambit). -This rest of this section documents the interface for a base table -implementation from which the @ref{Relational Database} package -constructs a Relational system. It will be of interest primarily to -those wishing to port or write new base-table implementations. +@subsection Notes -All of these functions are accessed through a single procedure by -calling that procedure with the symbol name of the operation. A -procedure will be returned if that operation is supported and @code{#f} -otherwise. For example: +All R4RS syntactic forms are defined, including @code{delay}. Along +with @code{delay} are simple definitions for @code{make-promise} (into +which @code{delay} expressions expand) and @code{force}.@refill -@example -@group -(require 'alist-table) -(define open-base (alist-table 'make-base)) -make-base @result{} *a procedure* -(define foo (alist-table 'foo)) -foo @result{} #f -@end group -@end example +@code{syntax-rules} and @code{with-syntax} (described in @cite{TR356}) +are defined.@refill -@defun make-base filename key-dimension column-types -Returns a new, open, low-level database (collection of tables) -associated with @var{filename}. This returned database has an empty -table associated with @var{catalog-id}. The positive integer -@var{key-dimension} is the number of keys composed to make a -@var{primary-key} for the catalog table. The list of symbols -@var{column-types} describes the types of each column for that table. -If the database cannot be created as specified, @code{#f} is returned. - -Calling the @code{close-base} method on this database and possibly other -operations will cause @var{filename} to be written to. If -@var{filename} is @code{#f} a temporary, non-disk based database will be -created if such can be supported by the base table implelentation. -@end defun +@code{syntax-case} is actually defined as a macro that expands into +calls to the procedure @code{syntax-dispatch} and the core form +@code{syntax-lambda}; do not redefine these names.@refill -@defun open-base filename mutable -Returns an open low-level database associated with @var{filename}. If -@var{mutable?} is @code{#t}, this database will have methods capable of -effecting change to the database. If @var{mutable?} is @code{#f}, only -methods for inquiring the database will be available. If the database -cannot be opened as specified @code{#f} is returned. +Several other top-level bindings not documented in TR356 are created: +@itemize @bullet +@item the ``hooks'' in @file{hooks.ss} +@item the @code{build-} procedures in @file{output.ss} +@item @code{expand-syntax} (the expander) +@end itemize -Calling the @code{close-base} (and possibly other) method on a -@var{mutable?} database will cause @var{filename} to be written to. -@end defun +The syntax of define has been extended to allow @code{(define @var{id})}, +which assigns @var{id} to some unspecified value.@refill -@defun write-base lldb filename -Causes the low-level database @var{lldb} to be written to -@var{filename}. If the write is successful, also causes @var{lldb} to -henceforth be associated with @var{filename}. Calling the -@code{close-database} (and possibly other) method on @var{lldb} may -cause @var{filename} to be written to. If @var{filename} is @code{#f} -this database will be changed to a temporary, non-disk based database if -such can be supported by the underlying base table implelentation. If -the operations completed successfully, @code{#t} is returned. -Otherwise, @code{#f} is returned. -@end defun +We have attempted to maintain R4RS compatibility where possible. The +incompatibilities should be confined to @file{hooks.ss}. Please let us +know if there is some incompatibility that is not flagged as such.@refill -@defun sync-base lldb -Causes the file associated with the low-level database @var{lldb} to be -updated to reflect its current state. If the associated filename is -@code{#f}, no action is taken and @code{#f} is returned. If this -operation completes successfully, @code{#t} is returned. Otherwise, -@code{#f} is returned. -@end defun +Send bug reports, comments, suggestions, and questions to Kent Dybvig +(dyb@@iuvax.cs.indiana.edu). -@defun close-base lldb -Causes the low-level database @var{lldb} to be written to its associated -file (if any). If the write is successful, subsequent operations to -@var{lldb} will signal an error. If the operations complete -successfully, @code{#t} is returned. Otherwise, @code{#f} is returned. -@end defun +@subsection Note from maintainer -@defun make-table lldb key-dimension column-types -Returns the @var{base-id} for a new base table, otherwise returns -@code{#f}. The base table can then be opened using @code{(open-table -@var{lldb} @var{base-id})}. The positive integer @var{key-dimension} is -the number of keys composed to make a @var{primary-key} for this table. -The list of symbols @var{column-types} describes the types of each -column. -@end defun +Included with the @code{syntax-case} files was @file{structure.scm} +which defines a macro @code{define-structure}. There is no +documentation for this macro and it is not used by any code in SLIB. -@defvr Constant catalog-id -A constant @var{base-id} suitable for passing as a parameter to -@code{open-table}. @var{catalog-id} will be used as the base table for -the system catalog. -@end defvr +@node Fluid-Let, Yasos, Syntax-Case Macros, Scheme Syntax Extension Packages +@section Fluid-Let -@defun open-table lldb base-id key-dimension column-types -Returns a @var{handle} for an existing base table in the low-level -database @var{lldb} if that table exists and can be opened in the mode -indicated by @var{mutable?}, otherwise returns @code{#f}. +@code{(require 'fluid-let)} +@ftindex fluid-let -As with @code{make-table}, the positive integer @var{key-dimension} is -the number of keys composed to make a @var{primary-key} for this table. -The list of symbols @var{column-types} describes the types of each -column. -@end defun +@deffn Syntax fluid-let @code{(@var{bindings} @dots{})} @var{forms}@dots{} +@end deffn +@lisp +(fluid-let ((@var{variable} @var{init}) @dots{}) + @var{expression} @var{expression} @dots{}) +@end lisp -@defun kill-table lldb base-id key-dimension column-types -Returns @code{#t} if the base table associated with @var{base-id} was -removed from the low level database @var{lldb}, and @code{#f} otherwise. -@end defun +The @var{init}s are evaluated in the current environment (in some +unspecified order), the current values of the @var{variable}s are saved, +the results are assigned to the @var{variable}s, the @var{expression}s +are evaluated sequentially in the current environment, the +@var{variable}s are restored to their original values, and the value of +the last @var{expression} is returned.@refill -@defun make-keyifier-1 type -Returns a procedure which accepts a single argument which must be of -type @var{type}. This returned procedure returns an object suitable for -being a @var{key} argument in the functions whose descriptions follow. +The syntax of this special form is similar to that of @code{let}, but +@code{fluid-let} temporarily rebinds existing @var{variable}s. Unlike +@code{let}, @code{fluid-let} creates no new bindings; instead it +@emph{assigns} the values of each @var{init} to the binding (determined +by the rules of lexical scoping) of its corresponding +@var{variable}.@refill -Any 2 arguments of the supported type passed to the returned function -which are not @code{equal?} must result in returned values which are not -@code{equal?}. -@end defun -@defun make-list-keyifier key-dimension types -The list of symbols @var{types} must have at least @var{key-dimension} -elements. Returns a procedure which accepts a list of length -@var{key-dimension} and whose types must corresopond to the types named -by @var{types}. This returned procedure combines the elements of its -list argument into an object suitable for being a @var{key} argument in -the functions whose descriptions follow. +@node Yasos, , Fluid-Let, Scheme Syntax Extension Packages +@section Yasos -Any 2 lists of supported types (which must at least include symbols and -non-negative integers) passed to the returned function which are not -@code{equal?} must result in returned values which are not -@code{equal?}. -@end defun +@c Much of the documentation in this section was written by Dave Love +@c (d.love@dl.ac.uk) -- don't blame Ken Dickey for its faults. +@c but we can blame him for not writing it! -@defun make-key-extractor key-dimension types column-number -Returns a procedure which accepts objects produced by application of the -result of @code{(make-list-keyifier @var{key-dimension} @var{types})}. -This procedure returns a @var{key} which is @code{equal?} to the -@var{column-number}th element of the list which was passed to create -@var{combined-key}. The list @var{types} must have at least -@var{key-dimension} elements. -@end defun +@code{(require 'oop)} or @code{(require 'yasos)} +@ftindex oop +@ftindex yasos -@defun make-key->list key-dimension types -Returns a procedure which accepts objects produced by application of the -result of @code{(make-list-keyifier @var{key-dimension} @var{types})}. -This procedure returns a list of @var{key}s which are elementwise -@code{equal?} to the list which was passed to create @var{combined-key}. -@end defun +`Yet Another Scheme Object System' is a simple object system for Scheme +based on the paper by Norman Adams and Jonathan Rees: @cite{Object +Oriented Programming in Scheme}, Proceedings of the 1988 ACM Conference +on LISP and Functional Programming, July 1988 [ACM #552880].@refill -@noindent -In the following functions, the @var{key} argument can always be assumed -to be the value returned by a call to a @emph{keyify} routine. +Another reference is: -@defun for-each-key handle procedure -Calls @var{procedure} once with each @var{key} in the table opened in -@var{handle} in an unspecified order. An unspecified value is returned. -@end defun +Ken Dickey. +@ifset html + +@end ifset +Scheming with Objects +@ifset html + +@end ifset +@cite{AI Expert} Volume 7, Number 10 (October 1992), pp. 24-33. -@defun map-key handle procedure -Returns a list of the values returned by calling @var{procedure} once -with each @var{key} in the table opened in @var{handle} in an -unspecified order. -@end defun +@menu +* Yasos terms:: Definitions and disclaimer. +* Yasos interface:: The Yasos macros and procedures. +* Setters:: Dylan-like setters in Yasos. +* Yasos examples:: Usage of Yasos and setters. +@end menu -@defun ordered-for-each-key handle procedure -Calls @var{procedure} once with each @var{key} in the table opened in -@var{handle} in the natural order for the types of the primary key -fields of that table. An unspecified value is returned. -@end defun +@node Yasos terms, Yasos interface, Yasos, Yasos +@subsection Terms -@defun present? handle key -Returns a non-@code{#f} value if there is a row associated with -@var{key} in the table opened in @var{handle} and @code{#f} otherwise. -@end defun +@table @asis +@item @dfn{Object} +Any Scheme data object. -@defun delete handle key -Removes the row associated with @var{key} from the table opened in -@var{handle}. An unspecified value is returned. -@end defun +@item @dfn{Instance} +An instance of the OO system; an @dfn{object}. -@defun make-getter key-dimension types -Returns a procedure which takes arguments @var{handle} and @var{key}. -This procedure returns a list of the non-primary values of the relation -(in the base table opened in @var{handle}) whose primary key is -@var{key} if it exists, and @code{#f} otherwise. -@end defun +@item @dfn{Operation} +A @var{method}. +@end table -@defun make-putter key-dimension types -Returns a procedure which takes arguments @var{handle} and @var{key} and -@var{value-list}. This procedure associates the primary key @var{key} -with the values in @var{value-list} (in the base table opened in -@var{handle}) and returns an unspecified value. -@end defun +@table @emph +@item Notes: +The object system supports multiple inheritance. An instance can +inherit from 0 or more ancestors. In the case of multiple inherited +operations with the same identity, the operation used is that from the +first ancestor which contains it (in the ancestor @code{let}). An +operation may be applied to any Scheme data object---not just instances. +As code which creates instances is just code, there are no @dfn{classes} +and no meta-@var{anything}. Method dispatch is by a procedure call a la +CLOS rather than by @code{send} syntax a la Smalltalk.@refill -@defun supported-type? symbol -Returns @code{#t} if @var{symbol} names a type allowed as a column value -by the implementation, and @code{#f} otherwise. At a minimum, an -implementation must support the types @code{integer}, @code{symbol}, -@code{string}, @code{boolean}, and @code{base-id}. -@end defun +@item Disclaimer: +There are a number of optimizations which can be made. This +implementation is expository (although performance should be quite +reasonable). See the L&FP paper for some suggestions.@refill +@end table -@defun supported-key-type? symbol -Returns @code{#t} if @var{symbol} names a type allowed as a key value by -the implementation, and @code{#f} otherwise. At a minimum, an -implementation must support the types @code{integer}, and @code{symbol}. -@end defun -@table @code -@item integer -Scheme exact integer. -@item symbol -Scheme symbol. -@item boolean -@code{#t} or @code{#f}. -@item base-id -Objects suitable for passing as the @var{base-id} parameter to -@code{open-table}. The value of @var{catalog-id} must be an acceptable -@code{base-id}. -@end table -@node Relational Database, Weight-Balanced Trees, Base Table, Data Structures -@section Relational Database -@code{(require 'relational-database)} -This package implements a database system inspired by the Relational -Model (@cite{E. F. Codd, A Relational Model of Data for Large Shared -Data Banks}). An SLIB relational database implementation can be created -from any @ref{Base Table} implementation. +@node Yasos interface, Setters, Yasos terms, Yasos +@subsection Interface -@menu -* Motivations:: Database Manifesto -* Creating and Opening Relational Databases:: -* Relational Database Operations:: -* Table Operations:: -* Catalog Representation:: -* Unresolved Issues:: -* Database Utilities:: 'database-utilities -@end menu - -@node Motivations, Creating and Opening Relational Databases, Relational Database, Relational Database -@subsection Motivations - -Most nontrivial programs contain databases: Makefiles, configure -scripts, file backup, calendars, editors, source revision control, CAD -systems, display managers, menu GUIs, games, parsers, debuggers, -profilers, and even error reporting are all rife with databases. Coding -databases is such a common activity in programming that many may not be -aware of how often they do it. - -A database often starts as a dispatch in a program. The author, perhaps -because of the need to make the dispatch configurable, the need for -correlating dispatch in other routines, or because of changes or growth, -devises a data structure to contain the information, a routine for -interpreting that data structure, and perhaps routines for augmenting -and modifying the stored data. The dispatch must be converted into this -form and tested. +@deffn Syntax define-operation @code{(}opname self arg @dots{}@code{)} @var{default-body} +Defines a default behavior for data objects which don't handle the +operation @var{opname}. The default default behavior (for an empty +@var{default-body}) is to generate an error.@refill +@end deffn -The programmer may need to devise an interactive program for enabling -easy examination and modification of the information contained in this -database. Often, in an attempt to foster modularity and avoid delays in -release, intermediate file formats for the database information are -devised. It often turns out that users prefer modifying these -intermediate files with a text editor to using the interactive program -in order to do operations (such as global changes) not forseen by the -program's author. +@deffn Syntax define-predicate opname? +Defines a predicate @var{opname?}, usually used for determining the +@dfn{type} of an object, such that @code{(@var{opname?} @var{object})} +returns @code{#t} if @var{object} has an operation @var{opname?} and +@code{#f} otherwise.@refill +@end deffn -In order to address this need, the concientous software engineer may -even provide a scripting language to allow users to make repetitive -database changes. Users will grumble that they need to read a large -manual and learn yet another programming language (even if it -@emph{almost} has language "xyz" syntax) in order to do simple -configuration. +@deffn Syntax object @code{((@var{name} @var{self} @var{arg} @dots{}) @var{body})} @dots{} +Returns an object (an instance of the object system) with operations. +Invoking @code{(@var{name} @var{object} @var{arg} @dots{}} executes the +@var{body} of the @var{object} with @var{self} bound to @var{object} and +with argument(s) @var{arg}@dots{}.@refill +@end deffn -All of these facilities need to be designed, coded, debugged, -documented, and supported; often causing what was very simple in concept -to become a major developement project. +@deffn Syntax object-with-ancestors @code{((}ancestor1 init1@code{)} @dots{}@code{)} operation @dots{} +A @code{let}-like form of @code{object} for multiple inheritance. It +returns an object inheriting the behaviour of @var{ancestor1} etc. An +operation will be invoked in an ancestor if the object itself does not +provide such a method. In the case of multiple inherited operations +with the same identity, the operation used is the one found in the first +ancestor in the ancestor list. +@end deffn -This view of databases just outlined is somewhat the reverse of the view -of the originators of the @dfn{Relational Model} of database -abstraction. The relational model was devised to unify and allow -interoperation of large multi-user databases running on diverse -platforms. A fairly general purpose "Comprehensive Language" for -database manipulations is mandated (but not specified) as part of the -relational model for databases. +@deffn Syntax operate-as component operation self arg @dots{} +Used in an operation definition (of @var{self}) to invoke the +@var{operation} in an ancestor @var{component} but maintain the object's +identity. Also known as ``send-to-super''.@refill +@end deffn -One aspect of the Relational Model of some importance is that the -"Comprehensive Language" must be expressible in some form which can be -stored in the database. This frees the programmer from having to make -programs data-driven in order to use a database. +@deffn Procedure print obj port +A default @code{print} operation is provided which is just @code{(format +@var{port} @var{obj})} (@xref{Format}) for non-instances and prints +@var{obj} preceded by @samp{#} for instances. +@end deffn -This package includes as one of its basic supported types Scheme -@dfn{expression}s. This type allows expressions as defined by the -Scheme standards to be stored in the database. Using @code{slib:eval} -retrieved expressions can be evaluated (in the top-level environment). -Scheme's @code{lambda} facilitates closure of environments, modularity, -etc. so that procedures (which could not be stored directly most -databases) can still be effectively retrieved. Since @code{slib:eval} -evaluates expressions in the top-level environment, built-in and user -defined procedures can be easily accessed by name. +@defun size obj +The default method returns the number of elements in @var{obj} if it is +a vector, string or list, @code{2} for a pair, @code{1} for a character +and by default id an error otherwise. Objects such as collections +(@xref{Collections}) may override the default in an obvious way.@refill +@end defun -This package's purpose is to standardize (through a common interface) -database creation and usage in Scheme programs. The relational model's -provision for inclusion of language expressions as data as well as the -description (in tables, of course) of all of its tables assures that -relational databases are powerful enough to assume the roles currently -played by thousands of ad-hoc routines and data formats. -@noindent -Such standardization to a relational-like model brings many benefits: -@itemize @bullet -@item -Tables, fields, domains, and types can be dealt with by name in -programs. -@item -The underlying database implementation can be changed (for -performance or other reasons) by changing a single line of code. -@item -The formats of tables can be easily extended or changed without -altering code. -@item -Consistency checks are specified as part of the table descriptions. -Changes in checks need only occur in one place. -@item -All the configuration information which the developer wishes to group -together is easily grouped, without needing to change programs aware of -only some of these tables. -@item -Generalized report generators, interactive entry programs, and other -database utilities can be part of a shared library. The burden of -adding configurability to a program is greatly reduced. -@item -Scheme is the "comprehensive language" for these databases. Scripting -for configuration no longer needs to be in a separate language with -additional documentation. -@item -Scheme's latent types mesh well with the strict typing and logical -requirements of the relational model. -@item -Portable formats allow easy interchange of data. The included table -descriptions help prevent misinterpretation of format. -@end itemize -@node Creating and Opening Relational Databases, Relational Database Operations, Motivations, Relational Database -@subsection Creating and Opening Relational Databases -@defun make-relational-system base-table-implementation +@node Setters, Yasos examples, Yasos interface, Yasos +@subsection Setters -Returns a procedure implementing a relational database using the -@var{base-table-implementation}. +@dfn{Setters} implement @dfn{generalized locations} for objects +associated with some sort of mutable state. A @dfn{getter} operation +retrieves a value from a generalized location and the corresponding +setter operation stores a value into the location. Only the getter is +named -- the setter is specified by a procedure call as below. (Dylan +uses special syntax.) Typically, but not necessarily, getters are +access operations to extract values from Yasos objects (@xref{Yasos}). +Several setters are predefined, corresponding to getters @code{car}, +@code{cdr}, @code{string-ref} and @code{vector-ref} e.g., @code{(setter +car)} is equivalent to @code{set-car!}. -All of the operations of a base table implementation are accessed -through a procedure defined by @code{require}ing that implementation. -Similarly, all of the operations of the relational database -implementation are accessed through the procedure returned by -@code{make-relational-system}. For instance, a new relational database -could be created from the procedure returned by -@code{make-relational-system} by: +This implementation of setters is similar to that in Dylan(TM) +(@cite{Dylan: An object-oriented dynamic language}, Apple Computer +Eastern Research and Technology). Common LISP provides similar +facilities through @code{setf}. +@defun setter getter +Returns the setter for the procedure @var{getter}. E.g., since +@code{string-ref} is the getter corresponding to a setter which is +actually @code{string-set!}: @example -(require 'alist-table) -(define relational-alist-system - (make-relational-system alist-table)) -(define create-alist-database - (relational-alist-system 'create-database)) -(define my-database - (create-alist-database "mydata.db")) +(define foo "foo") +((setter string-ref) foo 0 #\F) ; set element 0 of foo +foo @result{} "Foo" @end example @end defun -@noindent -What follows are the descriptions of the methods available from -relational system returned by a call to @code{make-relational-system}. +@deffn Syntax set place new-value +If @var{place} is a variable name, @code{set} is equivalent to +@code{set!}. Otherwise, @var{place} must have the form of a procedure +call, where the procedure name refers to a getter and the call indicates +an accessible generalized location, i.e., the call would return a value. +The return value of @code{set} is usually unspecified unless used with a +setter whose definition guarantees to return a useful value. +@example +(set (string-ref foo 2) #\O) ; generalized location with getter +foo @result{} "FoO" +(set foo "foo") ; like set! +foo @result{} "foo" +@end example +@end deffn -@defun create-database filename +@deffn Procedure add-setter getter setter +Add procedures @var{getter} and @var{setter} to the (inaccessible) list +of valid setter/getter pairs. @var{setter} implements the store +operation corresponding to the @var{getter} access operation for the +relevant state. The return value is unspecified. +@end deffn -Returns an open, nearly empty relational database associated with -@var{filename}. The only tables defined are the system catalog and -domain table. Calling the @code{close-database} method on this database -and possibly other operations will cause @var{filename} to be written -to. If @var{filename} is @code{#f} a temporary, non-disk based database -will be created if such can be supported by the underlying base table -implelentation. If the database cannot be created as specified -@code{#f} is returned. For the fields and layout of descriptor tables, -@xref{Catalog Representation} -@end defun +@deffn Procedure remove-setter-for getter +Removes the setter corresponding to the specified @var{getter} from the +list of valid setters. The return value is unspecified. +@end deffn -@defun open-database filename mutable? +@deffn Syntax define-access-operation getter-name +Shorthand for a Yasos @code{define-operation} defining an operation +@var{getter-name} that objects may support to return the value of some +mutable state. The default operation is to signal an error. The return +value is unspecified. +@end deffn -Returns an open relational database associated with @var{filename}. If -@var{mutable?} is @code{#t}, this database will have methods capable of -effecting change to the database. If @var{mutable?} is @code{#f}, only -methods for inquiring the database will be available. Calling the -@code{close-database} (and possibly other) method on a @var{mutable?} -database will cause @var{filename} to be written to. If the database -cannot be opened as specified @code{#f} is returned. -@end defun -@node Relational Database Operations, Table Operations, Creating and Opening Relational Databases, Relational Database -@subsection Relational Database Operations -@noindent -These are the descriptions of the methods available from an open -relational database. A method is retrieved from a database by calling -the database with the symbol name of the operation. For example: -@example -(define my-database - (create-alist-database "mydata.db")) -(define telephone-table-desc - ((my-database 'create-table) 'telephone-table-desc)) -@end example -@defun close-database -Causes the relational database to be written to its associated file (if -any). If the write is successful, subsequent operations to this -database will signal an error. If the operations completed -successfully, @code{#t} is returned. Otherwise, @code{#f} is returned. -@end defun +@node Yasos examples, , Setters, Yasos +@subsection Examples -@defun write-database filename -Causes the relational database to be written to @var{filename}. If the -write is successful, also causes the database to henceforth be -associated with @var{filename}. Calling the @code{close-database} (and -possibly other) method on this database will cause @var{filename} to be -written to. If @var{filename} is @code{#f} this database will be -changed to a temporary, non-disk based database if such can be supported -by the underlying base table implelentation. If the operations -completed successfully, @code{#t} is returned. Otherwise, @code{#f} is -returned. -@end defun +@lisp +;;; These definitions for PRINT and SIZE are already supplied by +(require 'yasos) -@defun table-exists? table-name -Returns @code{#t} if @var{table-name} exists in the system catalog, -otherwise returns @code{#f}. -@end defun +(define-operation (print obj port) + (format port + (if (instance? obj) "#" "~s") + obj)) -@defun open-table table-name mutable? -Returns a @dfn{methods} procedure for an existing relational table in -this database if it exists and can be opened in the mode indicated by -@var{mutable?}, otherwise returns @code{#f}. -@end defun +(define-operation (size obj) + (cond + ((vector? obj) (vector-length obj)) + ((list? obj) (length obj)) + ((pair? obj) 2) + ((string? obj) (string-length obj)) + ((char? obj) 1) + (else + (error "Operation not supported: size" obj)))) -@noindent -These methods will be present only in databases which are -@var{mutable?}. +(define-predicate cell?) +(define-operation (fetch obj)) +(define-operation (store! obj newValue)) -@defun delete-table table-name -Removes and returns the @var{table-name} row from the system catalog if -the table or view associated with @var{table-name} gets removed from the -database, and @code{#f} otherwise. -@end defun +(define (make-cell value) + (object + ((cell? self) #t) + ((fetch self) value) + ((store! self newValue) + (set! value newValue) + newValue) + ((size self) 1) + ((print self port) + (format port "#" (fetch self))))) -@defun create-table table-desc-name -Returns a methods procedure for a new (open) relational table for -describing the columns of a new base table in this database, otherwise -returns @code{#f}. For the fields and layout of descriptor tables, -@xref{Catalog Representation}. +(define-operation (discard obj value) + (format #t "Discarding ~s~%" value)) -@defunx create-table table-name table-desc-name -Returns a methods procedure for a new (open) relational table with -columns as described by @var{table-desc-name}, otherwise returns -@code{#f}. -@end defun +(define (make-filtered-cell value filter) + (object-with-ancestors ((cell (make-cell value))) + ((store! self newValue) + (if (filter newValue) + (store! cell newValue) + (discard self newValue))))) -@defun create-view ?? -@defunx project-table ?? -@defunx restrict-table ?? -@defunx cart-prod-tables ?? -Not yet implemented. -@end defun +(define-predicate array?) +(define-operation (array-ref array index)) +(define-operation (array-set! array index value)) -@node Table Operations, Catalog Representation, Relational Database Operations, Relational Database -@subsection Table Operations +(define (make-array num-slots) + (let ((anArray (make-vector num-slots))) + (object + ((array? self) #t) + ((size self) num-slots) + ((array-ref self index) (vector-ref anArray index)) + ((array-set! self index newValue) (vector-set! anArray index newValue)) + ((print self port) (format port "#" (size self)))))) + +(define-operation (position obj)) +(define-operation (discarded-value obj)) + +(define (make-cell-with-history value filter size) + (let ((pos 0) (most-recent-discard #f)) + (object-with-ancestors + ((cell (make-filtered-call value filter)) + (sequence (make-array size))) + ((array? self) #f) + ((position self) pos) + ((store! self newValue) + (operate-as cell store! self newValue) + (array-set! self pos newValue) + (set! pos (+ pos 1))) + ((discard self value) + (set! most-recent-discard value)) + ((discarded-value self) most-recent-discard) + ((print self port) + (format port "#" (fetch self)))))) + +(define-access-operation fetch) +(add-setter fetch store!) +(define foo (make-cell 1)) +(print foo #f) +@result{} "#" +(set (fetch foo) 2) +@result{} +(print foo #f) +@result{} "#" +(fetch foo) +@result{} 2 +@end lisp + +@node Textual Conversion Packages, Mathematical Packages, Scheme Syntax Extension Packages, Top +@chapter Textual Conversion Packages + +@menu +* Precedence Parsing:: +* Format:: Common-Lisp Format +* Standard Formatted I/O:: Posix printf and scanf +* Program Arguments:: Commands and Options. +* Printing Scheme:: Nicely +* Time and Date:: +* Vector Graphics:: +@end menu + + +@node Precedence Parsing, Format, Textual Conversion Packages, Textual Conversion Packages +@section Precedence Parsing + +@code{(require 'precedence-parse)} or @code{(require 'parse)} +@ftindex parse +@ftindex precedence @noindent -These are the descriptions of the methods available from an open -relational table. A method is retrieved from a table by calling -the table with the symbol name of the operation. For example: +This package implements: -@example -@group -(define telephone-table-desc - ((my-database 'create-table) 'telephone-table-desc)) -(require 'common-list-functions) -(define ndrp (telephone-table-desc 'row:insert)) -(ndrp '(1 #t name #f string)) -(ndrp '(2 #f telephone - (lambda (d) - (and (string? d) (> (string-length d) 2) - (every - (lambda (c) - (memv c '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 - #\+ #\( #\ #\) #\-))) - (string->list d)))) - string)) -@end group -@end example +@itemize @bullet +@item +a Pratt style precedence parser; +@item +a @dfn{tokenizer} which congeals tokens according to assigned classes of +constituent characters; +@item +procedures giving direct control of parser rulesets; +@item +procedures for higher level specification of rulesets. +@end itemize + +@menu +* Precedence Parsing Overview:: +* Ruleset Definition and Use:: +* Token definition:: +* Nud and Led Definition:: +* Grammar Rule Definition:: +@end menu + +@node Precedence Parsing Overview, Ruleset Definition and Use, Precedence Parsing, Precedence Parsing +@subsection Precedence Parsing Overview @noindent -Operations on a single column of a table are retrieved by giving the -column name as the second argument to the methods procedure. For -example: +This package offers improvements over previous parsers. + +@itemize @bullet +@item +Common computer language constructs are concisely specified. +@item +Grammars can be changed dynamically. Operators can be assigned +different meanings within a lexical context. +@item +Rulesets don't need compilation. Grammars can be changed incrementally. +@item +Operator precedence is specified by integers. +@item +All possibilities of bad input are handled @footnote{How do I know this? +I parsed 250kbyte of random input (an e-mail file) with a non-trivial +grammar utilizing all constructs.} and return as much structure as was +parsed when the error occured; The symbol @code{?} is substituted for +missing input. +@end itemize +@noindent +Here are the higher-level syntax types and an example of each. +Precedence considerations are omitted for clarity. @xref{Grammar +Rule Definition} for full details. +@deftp Grammar nofix bye exit +@example +bye +@end example +calls the function @code{exit} with no arguments. +@end deftp +@deftp Grammar prefix - negate +@example +- 42 +@end example +Calls the function @code{negate} with the argument @code{42}. +@end deftp +@deftp Grammar infix - difference +@example +x - y +@end example +Calls the function @code{difference} with arguments @code{x} and @code{y}. +@end deftp +@deftp Grammar nary + sum +@example +x + y + z +@end example +Calls the function @code{sum} with arguments @code{x}, @code{y}, and +@code{y}. +@end deftp +@deftp Grammar postfix ! factorial +@example +5 ! +@end example +Calls the function @code{factorial} with the argument @code{5}. +@end deftp +@deftp Grammar prestfix set set! +@example +set foo bar +@end example +Calls the function @code{set!} with the arguments @code{foo} and +@code{bar}. +@end deftp +@deftp Grammar commentfix /* */ +@example +/* almost any text here */ +@end example +Ignores the comment delimited by @code{/*} and @code{*/}. +@end deftp +@deftp Grammar matchfix @{ list @} +@example +@{0, 1, 2@} +@end example +Calls the function @code{list} with the arguments @code{0}, @code{1}, +and @code{2}. +@end deftp +@deftp Grammar inmatchfix ( funcall ) +@example +f(x, y) +@end example +Calls the function @code{funcall} with the arguments @code{f}, @code{x}, +and @code{y}. +@end deftp +@deftp Grammar delim ; @example -(define column-ids ((telephone-table-desc 'get* 'column-number))) +set foo bar; @end example +delimits the extent of the restfix operator @code{set}. +@end deftp + + +@node Ruleset Definition and Use, Token definition, Precedence Parsing Overview, Precedence Parsing +@subsection Ruleset Definition and Use + +@defvar *syn-defs* +A grammar is built by one or more calls to @code{prec:define-grammar}. +The rules are appended to @var{*syn-defs*}. The value of +@var{*syn-defs*} is the grammar suitable for passing as an argument to +@code{prec:parse}. +@end defvar + +@defvr Constant *syn-ignore-whitespace* +Is a nearly empty grammar with whitespace characters set to group 0, +which means they will not be made into tokens. Most rulesets will want +to start with @code{*syn-ignore-whitespace*} +@end defvr @noindent -Some operations described below require primary key arguments. Primary -keys arguments are denoted @var{key1} @var{key2} @dots{}. It is an -error to call an operation for a table which takes primary key arguments -with the wrong number of primary keys for that table. +In order to start defining a grammar, either +@example +(set! *syn-defs* '()) +@end example @noindent -The term @dfn{row} used below refers to a Scheme list of values (one for -each column) in the order specified in the descriptor (table) for this -table. Missing values appear as @code{#f}. Primary keys may not -be missing. +or -@defun get key1 key2 @dots{} -Returns the value for the specified column of the row associated with -primary keys @var{key1}, @var{key2} @dots{} if it exists, or @code{#f} -otherwise. +@example +(set! *syn-defs* *syn-ignore-whitespace*) +@end example -@defunx get* -Returns a list of the values for the specified column for all rows in -this table. +@defun prec:define-grammar rule1 @dots{} +Appends @var{rule1} @dots{} to @var{*syn-defs*}. +@code{prec:define-grammar} is used to define both the character classes +and rules for tokens. +@end defun -@defunx row:retrieve key1 key2 @dots{} -Returns the row associated with primary keys @var{key1}, @var{key2} -@dots{} if it exists, or @code{#f} otherwise. +@noindent +Once your grammar is defined, save the value of @code{*syn-defs*} in a +variable (for use when calling @code{prec:parse}). -@defunx row:retrieve* -Returns a list of all rows in this table. -@end defun +@example +(define my-ruleset *syn-defs*) +@end example -@defun row:remove key1 key2 @dots{} -Removes and returns the row associated with primary keys @var{key1}, -@var{key2} @dots{} if it exists, or @code{#f} otherwise. +@defun prec:parse ruleset delim +@defunx prec:parse ruleset delim port +The @var{ruleset} argument must be a list of rules as constructed by +@code{prec:define-grammar} and extracted from @var{*syn-defs*}. -@defunx row:remove* -Removes and returns a list of all rows in this table. -@end defun +The token @var{delim} may be a character, symbol, or string. A +character @var{delim} argument will match only a character token; i.e. a +character for which no token-group is assigned. A symbols or string +will match only a token string; i.e. a token resulting from a token +group. -@defun row:delete key1 key2 @dots{} -Deletes the row associated with primary keys @var{key1}, @var{key2} -@dots{} if it exists. The value returned is unspecified. +@code{prec:parse} reads a @var{ruleset} grammar expression delimited +by @var{delim} from the given input @var{port}. @code{prec:parse} +returns the next object parsable from the given input @var{port}, +updating @var{port} to point to the first character past the end of the +external representation of the object. -@defunx row:delete* -Deletes all rows in this table. The value returned is unspecified. The -descriptor table and catalog entry for this table are not affected. +If an end of file is encountered in the input before any characters are +found that can begin an object, then an end of file object is returned. +If a delimiter (such as @var{delim}) is found before any characters are +found that can begin an object, then @code{#f} is returned. + +The @var{port} argument may be omitted, in which case it defaults to the +value returned by @code{current-input-port}. It is an error to parse +from a closed port. +@findex current-input-port @end defun -@defun row:update row -Adds the row, @var{row}, to this table. If a row for the primary key(s) -specified by @var{row} already exists in this table, it will be -overwritten. The value returned is unspecified. +@node Token definition, Nud and Led Definition, Ruleset Definition and Use, Precedence Parsing +@subsection Token definition -@defunx row:update* rows -Adds each row in the list @var{rows}, to this table. If a row for the -primary key specified by an element of @var{rows} already exists in this -table, it will be overwritten. The value returned is unspecified. -@end defun +@defun tok:char-group group chars chars-proc +The argument @var{chars} may be a single character, a list of +characters, or a string. Each character in @var{chars} is treated as +though @code{tok:char-group} was called with that character alone. -@defun row:insert row -Adds the row @var{row} to this table. If a row for the primary key(s) -specified by @var{row} already exists in this table an error is -signaled. The value returned is unspecified. +The argument @var{chars-proc} must be a procedure of one argument, a +list of characters. After @code{tokenize} has finished +accumulating the characters for a token, it calls @var{chars-proc} with +the list of characters. The value returned is the token which +@code{tokenize} returns. -@defunx row:insert* rows -Adds each row in the list @var{rows}, to this table. If a row for the -primary key specified by an element of @var{rows} already exists in this -table, an error is signaled. The value returned is unspecified. -@end defun +The argument @var{group} may be an exact integer or a procedure of one +character argument. The following discussion concerns the treatment +which the tokenizing routine, @code{tokenize}, will accord to characters +on the basis of their groups. -@defun for-each-row proc -Calls @var{proc} with each @var{row} in this table in the natural -ordering for the primary key types. @emph{Real} relational programmers -would use some least-upper-bound join for every row to get them in -order; But we don't have joins yet. -@end defun +When @var{group} is a non-zero integer, characters whose group number is +equal to or exactly one less than @var{group} will continue to +accumulate. Any other character causes the accumulation to stop (until +a new token is to be read). -@defun close-table -Subsequent operations to this table will signal an error. +The @var{group} of zero is special. These characters are ignored when +parsed pending a token, and stop the accumulation of token characters +when the accumulation has already begun. Whitespace characters are +usually put in group 0. + +If @var{group} is a procedure, then, when triggerd by the occurence of +an initial (no accumulation) @var{chars} character, this procedure will +be repeatedly called with each successive character from the input +stream until the @var{group} procedure returns a non-false value. @end defun -@defvr Constant column-names -@defvrx Constant column-foreigns -@defvrx Constant column-domains -@defvrx Constant column-types -Return a list of the column names, foreign-key table names, domain -names, or type names respectively for this table. These 4 methods are -different from the others in that the list is returned, rather than a -procedure to obtain the list. +@noindent +The following convenient constants are provided for use with +@code{tok:char-group}. -@defvrx Constant primary-limit -Returns the number of primary keys fields in the relations in this -table. +@defvr Constant tok:decimal-digits +Is the string @code{"0123456789"}. +@end defvr +@defvr Constant tok:upper-case +Is the string consisting of all upper-case letters +("ABCDEFGHIJKLMNOPQRSTUVWXYZ"). +@end defvr +@defvr Constant tok:lower-case +Is the string consisting of all lower-case letters +("abcdefghijklmnopqrstuvwxyz"). +@end defvr +@defvr Constant tok:whitespaces +Is the string consisting of all characters between 0 and 255 for which +@code{char-whitespace?} returns true. @end defvr -@node Catalog Representation, Unresolved Issues, Table Operations, Relational Database -@subsection Catalog Representation -@noindent -Each database (in an implementation) has a @dfn{system catalog} which -describes all the user accessible tables in that database (including -itself). +@node Nud and Led Definition, Grammar Rule Definition, Token definition, Precedence Parsing +@subsection Nud and Led Definition + +This section describes advanced features. You can skip this section on +first reading. @noindent -The system catalog base table has the following fields. @code{PRI} -indicates a primary key for that table. +The @dfn{Null Denotation} (or @dfn{nud}) +@cindex Null Denotation, nud +of a token is the procedure and arguments applying for that token when +@dfn{Left}, an unclaimed parsed expression is not extant. -@example -@group -PRI table-name - column-limit the highest column number - coltab-name descriptor table name - bastab-id data base table identifier - user-integrity-rule - view-procedure A scheme thunk which, when called, - produces a handle for the view. coltab - and bastab are specified if and only if - view-procedure is not. -@end group -@end example +@noindent +The @dfn{Left Denotation} (or @dfn{led}) +@cindex Left Denotation, led +of a token is the procedure, arguments, and lbp applying for that token +when there is a @dfn{Left}, an unclaimed parsed expression. @noindent -Descriptors for base tables (not views) are tables (pointed to by -system catalog). Descriptor (base) tables have the fields: +In his paper, -@example -@group -PRI column-number sequential integers from 1 - primary-key? boolean TRUE for primary key components - column-name - column-integrity-rule - domain-name -@end group -@end example +@quotation +Pratt, V. R. +Top Down Operator Precendence. +@cite{SIGACT/SIGPLAN Symposium on Principles of Programming Languages}, +Boston, 1973, pages 41-51 +@end quotation -@noindent -A @dfn{primary key} is any column marked as @code{primary-key?} in the -corresponding descriptor table. All the @code{primary-key?} columns -must have lower column numbers than any non-@code{primary-key?} columns. -Every table must have at least one primary key. Primary keys must be -sufficient to distinguish all rows from each other in the table. All of -the system defined tables have a single primary key. +the @dfn{left binding power} (or @dfn{lbp}) was an independent property +of tokens. I think this was done in order to allow tokens with NUDs but +not LEDs to also be used as delimiters, which was a problem for +statically defined syntaxes. It turns out that @emph{dynamically +binding} NUDs and LEDs allows them independence. @noindent -This package currently supports tables having from 1 to 4 primary keys -if there are non-primary columns, and any (natural) number if @emph{all} -columns are primary keys. If you need more than 4 primary keys, I would -like to hear what you are doing! +For the rule-defining procedures that follow, the variable @var{tk} may +be a character, string, or symbol, or a list composed of characters, +strings, and symbols. Each element of @var{tk} is treated as though the +procedure were called for each element. @noindent -A @dfn{domain} is a category describing the allowable values to occur in -a column. It is described by a (base) table with the fields: +Character @var{tk} arguments will match only character tokens; +i.e. characters for which no token-group is assigned. Symbols and +strings will both match token strings; i.e. tokens resulting from token +groups. -@example -@group -PRI domain-name - foreign-table - domain-integrity-rule - type-id - type-param -@end group -@end example +@defun prec:make-nud tk sop arg1 @dots{} +Returns a rule specifying that @var{sop} be called when @var{tk} is +parsed. If @var{sop} is a procedure, it is called with @var{tk} and +@var{arg1} @dots{} as its arguments; the resulting value is incorporated +into the expression being built. Otherwise, @code{(list @var{sop} +@var{arg1} @dots{})} is incorporated. +@end defun @noindent -The @dfn{type-id} field value is a symbol. This symbol may be used by -the underlying base table implementation in storing that field. +If no NUD has been defined for a token; then if that token is a string, +it is converted to a symbol and returned; if not a string, the token is +returned. -@noindent -If the @code{foreign-table} field is non-@code{#f} then that field names -a table from the catalog. The values for that domain must match a -primary key of the table referenced by the @var{type-param} (or -@code{#f}, if allowed). This package currently does not support -composite foreign-keys. +@defun prec:make-led tk sop arg1 @dots{} +Returns a rule specifying that @var{sop} be called when @var{tk} is +parsed and @var{left} has an unclaimed parsed expression. If @var{sop} +is a procedure, it is called with @var{left}, @var{tk}, and @var{arg1} +@dots{} as its arguments; the resulting value is incorporated into the +expression being built. Otherwise, @var{left} is incorporated. +@end defun @noindent -The types for which support is planned are: -@example -@group - atom - symbol - string [] - number [] - money - date-time - boolean - - foreign-key - expression - virtual -@end group -@end example +If no LED has been defined for a token, and @var{left} is set, the +parser issues a warning. -@node Unresolved Issues, Database Utilities, Catalog Representation, Relational Database -@subsection Unresolved Issues +@node Grammar Rule Definition, , Nud and Led Definition, Precedence Parsing +@subsection Grammar Rule Definition -Although @file{rdms.scm} is not large I found it very difficult to write -(six rewrites). I am not aware of any other examples of a generalized -relational system (although there is little new in CS). I left out -several aspects of the Relational model in order to simplify the job. -The major features lacking (which might be addressed portably) are -views, transaction boundaries, and protection. +@noindent +Here are procedures for defining rules for the syntax types introduced +in @ref{Precedence Parsing Overview}. -Protection needs a model for specifying priveledges. Given how -operations are accessed from handles it should not be difficult to -restrict table accesses to those allowed for that user. +@noindent +For the rule-defining procedures that follow, the variable @var{tk} may +be a character, string, or symbol, or a list composed of characters, +strings, and symbols. Each element of @var{tk} is treated as though the +procedure were called for each element. -The system catalog has a field called @code{view-procedure}. This -should allow a purely functional implementation of views. This will -work but is unsatisfying for views resulting from a @dfn{select}ion -(subset of rows); for whole table operations it will not be possible to -reduce the number of keys scanned over when the selection is specified -only by an opaque procedure. +@noindent +For procedures prec:delim, @dots{}, prec:prestfix, if the @var{sop} +argument is @code{#f}, then the token which triggered this rule is +converted to a symbol and returned. A false @var{sop} argument to the +procedures prec:commentfix, prec:matchfix, or prec:inmatchfix has a +different meaning. -Transaction boundaries present the most intriguing area. Transaction -boundaries are actually a feature of the "Comprehensive Language" of the -Relational database and not of the database. Scheme would seem to -provide the opportunity for an extremely clean semantics for transaction -boundaries since the builtin procedures with side effects are small in -number and easily identified. +@noindent +Character @var{tk} arguments will match only character tokens; +i.e. characters for which no token-group is assigned. Symbols and +strings will both match token strings; i.e. tokens resulting from token +groups. -These side-effect builtin procedures might all be portably redefined to -versions which properly handled transactions. Compiled library routines -would need to be recompiled as well. Many system extensions -(delete-file, system, etc.) would also need to be redefined. +@defun prec:delim tk +Returns a rule specifying that @var{tk} should not be returned from +parsing; i.e. @var{tk}'s function is purely syntactic. The end-of-file +is always treated as a delimiter. +@end defun -@noindent -There are 2 scope issues that must be resolved for multiprocess -transaction boundaries: +@defun prec:nofix tk sop +Returns a rule specifying the following actions take place when @var{tk} +is parsed: +@itemize @bullet +@item +If @var{sop} is a procedure, it is called with no arguments; the +resulting value is incorporated into the expression being built. +Otherwise, the list of @var{sop} is incorporated. +@end itemize +@end defun -@table @asis -@item Process scope -The actions captured by a transaction should be only for the process -which invoked the start of transaction. Although standard Scheme does -not provide process primitives as such, @code{dynamic-wind} would -provide a workable hook into process switching for many implementations. -@item Shared utilities with state -Some shared utilities have state which should @emph{not} be part of a -transaction. An example would be calling a pseudo-random number -generator. If the success of a transaction depended on the -pseudo-random number and failed, the state of the generator would be set -back. Subsequent calls would keep returning the same number and keep -failing. +@defun prec:prefix tk sop bp rule1 @dots{} +Returns a rule specifying the following actions take place when @var{tk} +is parsed: +@itemize @bullet +@item +The rules @var{rule1} @dots{} augment and, in case of conflict, override +rules currently in effect. +@item +@code{prec:parse1} is called with binding-power @var{bp}. +@item +If @var{sop} is a procedure, it is called with the expression returned +from @code{prec:parse1}; the resulting value is incorporated into the +expression being built. Otherwise, the list of @var{sop} and the +expression returned from @code{prec:parse1} is incorporated. +@item +The ruleset in effect before @var{tk} was parsed is restored; +@var{rule1} @dots{} are forgotten. +@end itemize +@end defun -Pseudo-random number generators are not reentrant and so would require -locks in order to operate properly in a multiprocess environment. Are -all examples of utilities whose state should not part of transactions -also non-reentrant? If so, perhaps suspending transaction capture for -the duration of locks would fix it. -@end table +@defun prec:infix tk sop lbp bp rule1 @dots{} +Returns a rule declaring the left-binding-precedence of the token +@var{tk} is @var{lbp} and specifying the following actions take place +when @var{tk} is parsed: +@itemize @bullet +@item +The rules @var{rule1} @dots{} augment and, in case of conflict, override +rules currently in effect. +@item +One expression is parsed with binding-power @var{lbp}. If instead a delimiter +is encountered, a warning is issued. +@item +If @var{sop} is a procedure, it is applied to the list of @var{left} and +the parsed expression; the resulting value is incorporated into the +expression being built. Otherwise, the list of @var{sop}, the +@var{left} expression, and the parsed expression is incorporated. +@item +The ruleset in effect before @var{tk} was parsed is restored; +@var{rule1} @dots{} are forgotten. +@end itemize +@end defun -@node Database Utilities, , Unresolved Issues, Relational Database -@subsection Database Utilities +@defun prec:nary tk sop bp +Returns a rule declaring the left-binding-precedence of the token +@var{tk} is @var{bp} and specifying the following actions take place +when @var{tk} is parsed: +@itemize @bullet +@item +Expressions are parsed with binding-power @var{bp} as far as they are +interleaved with the token @var{tk}. +@item +If @var{sop} is a procedure, it is applied to the list of @var{left} and +the parsed expressions; the resulting value is incorporated into the +expression being built. Otherwise, the list of @var{sop}, the +@var{left} expression, and the parsed expressions is incorporated. +@end itemize +@end defun -@code{(require 'database-utilities)} +@defun prec:postfix tk sop lbp +Returns a rule declaring the left-binding-precedence of the token +@var{tk} is @var{lbp} and specifying the following actions take place +when @var{tk} is parsed: +@itemize @bullet +@item +If @var{sop} is a procedure, it is called with the @var{left} expression; +the resulting value is incorporated into the expression being built. +Otherwise, the list of @var{sop} and the @var{left} expression is +incorporated. +@end itemize +@end defun -@noindent -This enhancement wraps a utility layer on @code{relational-database} -which provides: +@defun prec:prestfix tk sop bp rule1 @dots{} +Returns a rule specifying the following actions take place when @var{tk} +is parsed: @itemize @bullet @item -Automatic loading of the appropriate base-table package when opening a -database. +The rules @var{rule1} @dots{} augment and, in case of conflict, override +rules currently in effect. @item -Automatic execution of initialization commands stored in database. +Expressions are parsed with binding-power @var{bp} until a delimiter is +reached. @item -Transparent execution of database commands stored in @code{*commands*} -table in database. +If @var{sop} is a procedure, it is applied to the list of parsed +expressions; the resulting value is incorporated into the expression +being built. Otherwise, the list of @var{sop} and the parsed +expressions is incorporated. +@item +The ruleset in effect before @var{tk} was parsed is restored; +@var{rule1} @dots{} are forgotten. @end itemize +@end defun -@noindent -Also included are utilities which provide: +@defun prec:commentfix tk stp match rule1 @dots{} +Returns rules specifying the following actions take place when @var{tk} +is parsed: @itemize @bullet @item -Data definition from Scheme lists and +The rules @var{rule1} @dots{} augment and, in case of conflict, override +rules currently in effect. @item -Report generation +Characters are read untile and end-of-file or a sequence of characters +is read which matches the @emph{string} @var{match}. +@item +If @var{stp} is a procedure, it is called with the string of all that +was read between the @var{tk} and @var{match} (exclusive). +@item +The ruleset in effect before @var{tk} was parsed is restored; +@var{rule1} @dots{} are forgotten. @end itemize -@noindent -for any SLIB relational database. -@defun create-database filename base-table-type -Returns an open, nearly empty enhanced (with @code{*commands*} table) -relational database (with base-table type @var{base-table-type}) -associated with @var{filename}. +Parsing of commentfix syntax differs from the others in several ways. +It reads directly from input without tokenizing; It calls @var{stp} but +does not return its value; nay any value. I added the @var{stp} +argument so that comment text could be echoed. @end defun -@defun open-database filename -@defunx open-database filename base-table-type -Returns an open enchanced relational database associated with -@var{filename}. The database will be opened with base-table type -@var{base-table-type}) if supplied. If @var{base-table-type} is not -supplied, @code{open-database} will attempt to deduce the correct -base-table-type. If the database can not be opened or if it lacks the -@code{*commands*} table, @code{#f} is returned. +@defun prec:matchfix tk sop sep match rule1 @dots{} +Returns a rule specifying the following actions take place when @var{tk} +is parsed: +@itemize @bullet +@item +The rules @var{rule1} @dots{} augment and, in case of conflict, override +rules currently in effect. +@item +A rule declaring the token @var{match} a delimiter takes effect. +@item +Expressions are parsed with binding-power @code{0} until the token +@var{match} is reached. If the token @var{sep} does not appear between +each pair of expressions parsed, a warning is issued. +@item +If @var{sop} is a procedure, it is applied to the list of parsed +expressions; the resulting value is incorporated into the expression +being built. Otherwise, the list of @var{sop} and the parsed +expressions is incorporated. +@item +The ruleset in effect before @var{tk} was parsed is restored; +@var{rule1} @dots{} are forgotten. +@end itemize +@end defun -@defunx open-database! filename -@defunx open-database! filename base-table-type -Returns @emph{mutable} open enchanced relational database @dots{} +@defun prec:inmatchfix tk sop sep match lbp rule1 @dots{} +Returns a rule declaring the left-binding-precedence of the token +@var{tk} is @var{lbp} and specifying the following actions take place +when @var{tk} is parsed: +@itemize @bullet +@item +The rules @var{rule1} @dots{} augment and, in case of conflict, override +rules currently in effect. +@item +A rule declaring the token @var{match} a delimiter takes effect. +@item +Expressions are parsed with binding-power @code{0} until the token +@var{match} is reached. If the token @var{sep} does not appear between +each pair of expressions parsed, a warning is issued. +@item +If @var{sop} is a procedure, it is applied to the list of @var{left} and +the parsed expressions; the resulting value is incorporated into the +expression being built. Otherwise, the list of @var{sop}, the +@var{left} expression, and the parsed expressions is incorporated. +@item +The ruleset in effect before @var{tk} was parsed is restored; +@var{rule1} @dots{} are forgotten. +@end itemize @end defun -@noindent -The table @code{*commands*} in an @dfn{enhanced} relational-database has -the fields (with domains): -@example -@group -PRI name symbol - parameters parameter-list - procedure expression - documentation string -@end group -@end example -The @code{parameters} field is a foreign key (domain -@code{parameter-list}) of the @code{*catalog-data*} table and should -have the value of a table described by @code{*parameter-columns*}. This -@code{parameter-list} table describes the arguments suitable for passing -to the associated command. The intent of this table is to be of a form -such that different user-interfaces (for instance, pull-down menus or -plain-text queries) can operate from the same table. A -@code{parameter-list} table has the following fields: -@example -@group -PRI index uint - name symbol - arity parameter-arity - domain domain - default expression - documentation string -@end group -@end example +@node Format, Standard Formatted I/O, Precedence Parsing, Textual Conversion Packages +@section Format (version 3.0) -The @code{arity} field can take the values: +@code{(require 'format)} +@ftindex format -@table @code -@item single -Requires a single parameter of the specified domain. -@item optional -A single parameter of the specified domain or zero parameters is -acceptable. -@item boolean -A single boolean parameter or zero parameters (in which case @code{#f} -is substituted) is acceptable. -@item nary -Any number of parameters of the specified domain are acceptable. The -argument passed to the command function is always a list of the -parameters. -@item nary1 -One or more of parameters of the specified domain are acceptable. The -argument passed to the command function is always a list of the -parameters. -@end table +@menu +* Format Interface:: +* Format Specification:: +@end menu -The @code{domain} field specifies the domain which a parameter or -parameters in the @code{index}th field must satisfy. +@node Format Interface, Format Specification, Format, Format +@subsection Format Interface -The @code{default} field is an expression whose value is either -@code{#f} or a procedure of no arguments which returns a parameter or -parameter list as appropriate. If the expression's value is @code{#f} -then no default is appropriate for this parameter. Note that since the -@code{default} procedure is called every time a default parameter is -needed for this column, @dfn{sticky} defaults can be implemented using -shared state with the domain-integrity-rule. - -@subsubheading Invoking Commands - -When an enhanced relational-database is called with a symbol which -matches a @var{name} in the @code{*commands*} table, the associated -procedure expression is evaluated and applied to the enhanced -relational-database. A procedure should then be returned which the user -can invoke on (optional) arguments. - -The command @code{*initialize*} is special. If present in the -@code{*commands*} table, @code{open-database} or @code{open-database!} -will return the value of the @code{*initialize*} command. Notice that -arbitrary code can be run when the @code{*initialize*} procedure is -automatically applied to the enhanced relational-database. - -Note also that if you wish to shadow or hide from the user -relational-database methods described in @ref{Relational Database -Operations}, this can be done by a dispatch in the closure returned by -the @code{*initialize*} expression rather than by entries in the -@code{*commands*} table if it is desired that the underlying methods -remain accessible to code in the @code{*commands*} table. - -@defun make-command-server rdb table-name -Returns a procedure of 2 arguments, a (symbol) command and a call-back -procedure. When this returned procedure is called, it looks up -@var{command} in table @var{table-name} and calls the call-back -procedure with arguments: -@table @var -@item command -The @var{command} -@item command-value -The result of evaluating the expression in the @var{procedure} field of -@var{table-name} and calling it with @var{rdb}. -@item parameter-name -A list of the @dfn{official} name of each parameter. Corresponds to the -@code{name} field of the @var{command}'s parameter-table. -@item positions -A list of the positive integer index of each parameter. Corresponds to -the @code{index} field of the @var{command}'s parameter-table. -@item arities -A list of the arities of each parameter. Corresponds to the -@code{arity} field of the @var{command}'s parameter-table. For a -description of @code{arity} see table above. -@item defaults -A list of the defaults for each parameter. Corresponds to -the @code{defaults} field of the @var{command}'s parameter-table. -@item domain-integrity-rules -A list of procedures (one for each parameter) which tests whether a -value for a parameter is acceptable for that parameter. The procedure -should be called with each datum in the list for @code{nary} arity -parameters. -@item aliases -A list of lists of @code{(@r{alias} @r{parameter-name})}. There can be -more than one alias per @var{parameter-name}. -@end table -@end defun - -For information about parameters, @xref{Parameter lists}. Here is an -example of setting up a command with arguments and parsing those -arguments from a @code{getopt} style argument list (@pxref{Getopt}). - -@example -(require 'database-utilities) -(require 'parameters) -(require 'getopt) - -(define my-rdb (create-database #f 'alist-table)) - -(define-tables my-rdb - '(foo-params - *parameter-columns* - *parameter-columns* - ((1 first-argument single string "hithere" "first argument") - (2 flag boolean boolean #f "a flag"))) - '(foo-pnames - ((name string)) - ((parameter-index uint)) - (("l" 1) - ("a" 2))) - '(my-commands - ((name symbol)) - ((parameters parameter-list) - (parameter-names parameter-name-translation) - (procedure expression) - (documentation string)) - ((foo - foo-params - foo-pnames - (lambda (rdb) (lambda (foo aflag) (print foo aflag))) - "test command arguments")))) - -(define (dbutil:serve-command-line rdb command-table - command argc argv) - (set! argv (if (vector? argv) (vector->list argv) argv)) - ((make-command-server rdb command-table) - command - (lambda (comname comval options positions - arities types defaults dirs aliases) - (apply comval (getopt->arglist argc argv options positions - arities types defaults dirs aliases))))) - -(define (test) - (set! *optind* 1) - (dbutil:serve-command-line - my-rdb 'my-commands 'foo 4 '("dummy" "-l" "foo" "-a"))) -(test) -@print{} -"foo" #t -@end example - -Some commands are defined in all extended relational-databases. The are -called just like @ref{Relational Database Operations}. +@defun format destination format-string . arguments +An almost complete implementation of Common LISP format description +according to the CL reference book @cite{Common LISP} from Guy L. +Steele, Digital Press. Backward compatible to most of the available +Scheme format implementations. -@defun add-domain domain-row -Adds @var{domain-row} to the @dfn{domains} table if there is no row in -the domains table associated with key @code{(car @var{domain-row})} and -returns @code{#t}. Otherwise returns @code{#f}. +Returns @code{#t}, @code{#f} or a string; has side effect of printing +according to @var{format-string}. If @var{destination} is @code{#t}, +the output is to the current output port and @code{#t} is returned. If +@var{destination} is @code{#f}, a formatted string is returned as the +result of the call. NEW: If @var{destination} is a string, +@var{destination} is regarded as the format string; @var{format-string} is +then the first argument and the output is returned as a string. If +@var{destination} is a number, the output is to the current error port +if available by the implementation. Otherwise @var{destination} must be +an output port and @code{#t} is returned.@refill -For the fields and layout of the domain table, @xref{Catalog -Representation} -@end defun +@var{format-string} must be a string. In case of a formatting error +format returns @code{#f} and prints a message on the current output or +error port. Characters are output as if the string were output by the +@code{display} function with the exception of those prefixed by a tilde +(~). For a detailed description of the @var{format-string} syntax +please consult a Common LISP format reference manual. For a test suite +to verify this format implementation load @file{formatst.scm}. Please +send bug reports to @code{lutzeb@@cs.tu-berlin.de}. -@defun delete-domain domain-name -Removes and returns the @var{domain-name} row from the @dfn{domains} -table. -@end defun +Note: @code{format} is not reentrant, i.e. only one @code{format}-call +may be executed at a time. -@defun domain-checker domain -Returns a procedure to check an argument for conformance to domain -@var{domain}. @end defun -@subheading Defining Tables - -@deffn Procedure define-tables rdb spec-0 @dots{} -Adds tables as specified in @var{spec-0} @dots{} to the open -relational-database @var{rdb}. Each @var{spec} has the form: - -@lisp -(@r{} @r{} @r{} @r{}) -@end lisp -or -@lisp -(@r{} @r{} @r{} @r{}) -@end lisp +@node Format Specification, , Format Interface, Format +@subsection Format Specification (Format version 3.0) -where @r{} is the table name, @r{} is the symbol -name of a descriptor table, @r{} and -@r{} describe the primary keys and other fields -respectively, and @r{} is a list of data rows to be added to the -table. +Please consult a Common LISP format reference manual for a detailed +description of the format string syntax. For a demonstration of the +implemented directives see @file{formatst.scm}.@refill -@r{} and @r{} are lists of field -descriptors of the form: +This implementation supports directive parameters and modifiers +(@code{:} and @code{@@} characters). Multiple parameters must be +separated by a comma (@code{,}). Parameters can be numerical parameters +(positive or negative), character parameters (prefixed by a quote +character (@code{'}), variable parameters (@code{v}), number of rest +arguments parameter (@code{#}), empty and default parameters. Directive +characters are case independent. The general form of a directive +is:@refill -@lisp -(@r{} @r{}) -@end lisp -or -@lisp -(@r{} @r{} @r{}) -@end lisp +@noindent +@var{directive} ::= ~@{@var{directive-parameter},@}[:][@@]@var{directive-character} -where @r{} is the column name, @r{} is the domain -of the column, and @r{} is an expression whose -value is a procedure of one argument (and returns non-@code{#f} to -signal an error). +@noindent +@var{directive-parameter} ::= [ [-|+]@{0-9@}+ | '@var{character} | v | # ] -If @r{} is not a defined domain name and it matches the name of -this table or an already defined (in one of @var{spec-0} @dots{}) single -key field table, a foriegn-key domain will be created for it. -@end deffn +@subsubsection Implemented CL Format Control Directives -@deffn Procedure create-report rdb destination report-name table -@deffnx Procedure create-report rdb destination report-name -The symbol @var{report-name} must be primary key in the table named -@code{*reports*} in the relational database @var{rdb}. -@var{destination} is a port, string, or symbol. If @var{destination} is -a: +Documentation syntax: Uppercase characters represent the corresponding +control directive characters. Lowercase characters represent control +directive parameter descriptions. @table @asis -@item port -The table is created as ascii text and written to that port. -@item string -The table is created as ascii text and written to the file named by -@var{destination}. -@item symbol -@var{destination} is the primary key for a row in the table named *printers*. +@item @code{~A} +Any (print as @code{display} does). +@table @asis +@item @code{~@@A} +left pad. +@item @code{~@var{mincol},@var{colinc},@var{minpad},@var{padchar}A} +full padding. @end table - -Each row in the table *reports* has the fields: - +@item @code{~S} +S-expression (print as @code{write} does). @table @asis -@item name -The report name. -@item default-table -The table to report on if none is specified. -@item header, footer -A @code{format} string. At the beginning and end of each page -respectively, @code{format} is called with this string and the (list of) -column-names of this table. -@item reporter -A @code{format} string. For each row in the table, @code{format} is -called with this string and the row. -@item minimum-break -The minimum number of lines into which the report lines for a row can be -broken. Use @code{0} if a row's lines should not be broken over page -boundaries. +@item @code{~@@S} +left pad. +@item @code{~@var{mincol},@var{colinc},@var{minpad},@var{padchar}S} +full padding. @end table - -Each row in the table *printers* has the fields: - +@item @code{~D} +Decimal. @table @asis -@item name -The printer name. -@item print-procedure -The procedure to call to actually print. +@item @code{~@@D} +print number sign always. +@item @code{~:D} +print comma separated. +@item @code{~@var{mincol},@var{padchar},@var{commachar}D} +padding. @end table - -The report is prepared as follows: - -@itemize -@item -@code{Format} (@pxref{Format}) is called with the @code{header} field -and the (list of) @code{column-names} of the table. -@item -@code{Format} is called with the @code{reporter} field and (on -successive calls) each record in the natural order for the table. A -count is kept of the number of newlines output by format. When the -number of newlines to be output exceeds the number of lines per page, -the set of lines will be broken if there are more than -@code{minimum-break} left on this page and the number of lines for this -row is larger or equal to twice @code{minimum-break}. -@item -@code{Format} is called with the @code{footer} field and the (list of) -@code{column-names} of the table. The footer field should not output a -newline. +@item @code{~X} +Hexadecimal. +@table @asis +@item @code{~@@X} +print number sign always. +@item @code{~:X} +print comma separated. +@item @code{~@var{mincol},@var{padchar},@var{commachar}X} +padding. +@end table +@item @code{~O} +Octal. +@table @asis +@item @code{~@@O} +print number sign always. +@item @code{~:O} +print comma separated. +@item @code{~@var{mincol},@var{padchar},@var{commachar}O} +padding. +@end table +@item @code{~B} +Binary. +@table @asis +@item @code{~@@B} +print number sign always. +@item @code{~:B} +print comma separated. +@item @code{~@var{mincol},@var{padchar},@var{commachar}B} +padding. +@end table +@item @code{~@var{n}R} +Radix @var{n}. +@table @asis +@item @code{~@var{n},@var{mincol},@var{padchar},@var{commachar}R} +padding. +@end table +@item @code{~@@R} +print a number as a Roman numeral. +@item @code{~:R} +print a number as an ordinal English number. +@item @code{~:@@R} +print a number as a cardinal English number. +@item @code{~P} +Plural. +@table @asis +@item @code{~@@P} +prints @code{y} and @code{ies}. +@item @code{~:P} +as @code{~P but jumps 1 argument backward.} +@item @code{~:@@P} +as @code{~@@P but jumps 1 argument backward.} +@end table +@item @code{~C} +Character. +@table @asis +@item @code{~@@C} +prints a character as the reader can understand it (i.e. @code{#\} prefixing). +@item @code{~:C} +prints a character as emacs does (eg. @code{^C} for ASCII 03). +@end table +@item @code{~F} +Fixed-format floating-point (prints a flonum like @var{mmm.nnn}). +@table @asis +@item @code{~@var{width},@var{digits},@var{scale},@var{overflowchar},@var{padchar}F} +@item @code{~@@F} +If the number is positive a plus sign is printed. +@end table +@item @code{~E} +Exponential floating-point (prints a flonum like @var{mmm.nnn}@code{E}@var{ee}). +@table @asis +@item @code{~@var{width},@var{digits},@var{exponentdigits},@var{scale},@var{overflowchar},@var{padchar},@var{exponentchar}E} +@item @code{~@@E} +If the number is positive a plus sign is printed. +@end table +@item @code{~G} +General floating-point (prints a flonum either fixed or exponential). +@table @asis +@item @code{~@var{width},@var{digits},@var{exponentdigits},@var{scale},@var{overflowchar},@var{padchar},@var{exponentchar}G} +@item @code{~@@G} +If the number is positive a plus sign is printed. +@end table +@item @code{~$} +Dollars floating-point (prints a flonum in fixed with signs separated). +@table @asis +@item @code{~@var{digits},@var{scale},@var{width},@var{padchar}$} +@item @code{~@@$} +If the number is positive a plus sign is printed. +@item @code{~:@@$} +A sign is always printed and appears before the padding. +@item @code{~:$} +The sign appears before the padding. +@end table +@item @code{~%} +Newline. +@table @asis +@item @code{~@var{n}%} +print @var{n} newlines. +@end table +@item @code{~&} +print newline if not at the beginning of the output line. +@table @asis +@item @code{~@var{n}&} +prints @code{~&} and then @var{n-1} newlines. +@end table +@item @code{~|} +Page Separator. +@table @asis +@item @code{~@var{n}|} +print @var{n} page separators. +@end table +@item @code{~~} +Tilde. +@table @asis +@item @code{~@var{n}~} +print @var{n} tildes. +@end table +@item @code{~} +Continuation Line. +@table @asis +@item @code{~:} +newline is ignored, white space left. +@item @code{~@@} +newline is left, white space ignored. +@end table +@item @code{~T} +Tabulation. +@table @asis +@item @code{~@@T} +relative tabulation. +@item @code{~@var{colnum,colinc}T} +full tabulation. +@end table +@item @code{~?} +Indirection (expects indirect arguments as a list). +@table @asis +@item @code{~@@?} +extracts indirect arguments from format arguments. +@end table +@item @code{~(@var{str}~)} +Case conversion (converts by @code{string-downcase}). +@table @asis +@item @code{~:(@var{str}~)} +converts by @code{string-capitalize}. +@item @code{~@@(@var{str}~)} +converts by @code{string-capitalize-first}. +@item @code{~:@@(@var{str}~)} +converts by @code{string-upcase}. +@end table +@item @code{~*} +Argument Jumping (jumps 1 argument forward). +@table @asis +@item @code{~@var{n}*} +jumps @var{n} arguments forward. +@item @code{~:*} +jumps 1 argument backward. +@item @code{~@var{n}:*} +jumps @var{n} arguments backward. +@item @code{~@@*} +jumps to the 0th argument. +@item @code{~@var{n}@@*} +jumps to the @var{n}th argument (beginning from 0) +@end table +@item @code{~[@var{str0}~;@var{str1}~;...~;@var{strn}~]} +Conditional Expression (numerical clause conditional). +@table @asis +@item @code{~@var{n}[} +take argument from @var{n}. +@item @code{~@@[} +true test conditional. +@item @code{~:[} +if-else-then conditional. +@item @code{~;} +clause separator. +@item @code{~:;} +default clause follows. +@end table +@item @code{~@{@var{str}~@}} +Iteration (args come from the next argument (a list)). +@table @asis +@item @code{~@var{n}@{} +at most @var{n} iterations. +@item @code{~:@{} +args from next arg (a list of lists). +@item @code{~@@@{} +args from the rest of arguments. +@item @code{~:@@@{} +args from the rest args (lists). +@end table +@item @code{~^} +Up and out. +@table @asis +@item @code{~@var{n}^} +aborts if @var{n} = 0 +@item @code{~@var{n},@var{m}^} +aborts if @var{n} = @var{m} +@item @code{~@var{n},@var{m},@var{k}^} +aborts if @var{n} <= @var{m} <= @var{k} +@end table +@end table + + +@subsubsection Not Implemented CL Format Control Directives + +@table @asis +@item @code{~:A} +print @code{#f} as an empty list (see below). +@item @code{~:S} +print @code{#f} as an empty list (see below). +@item @code{~<~>} +Justification. +@item @code{~:^} +(sorry I don't understand its semantics completely) +@end table + + +@subsubsection Extended, Replaced and Additional Control Directives + +@table @asis +@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}D} +@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}X} +@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}O} +@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}B} +@item @code{~@var{n},@var{mincol},@var{padchar},@var{commachar},@var{commawidth}R} +@var{commawidth} is the number of characters between two comma characters. +@end table + +@table @asis +@item @code{~I} +print a R4RS complex number as @code{~F~@@Fi} with passed parameters for +@code{~F}. +@item @code{~Y} +Pretty print formatting of an argument for scheme code lists. +@item @code{~K} +Same as @code{~?.} +@item @code{~!} +Flushes the output if format @var{destination} is a port. +@item @code{~_} +Print a @code{#\space} character +@table @asis +@item @code{~@var{n}_} +print @var{n} @code{#\space} characters. +@end table +@item @code{~/} +Print a @code{#\tab} character +@table @asis +@item @code{~@var{n}/} +print @var{n} @code{#\tab} characters. +@end table +@item @code{~@var{n}C} +Takes @var{n} as an integer representation for a character. No arguments +are consumed. @var{n} is converted to a character by +@code{integer->char}. @var{n} must be a positive decimal number.@refill +@item @code{~:S} +Print out readproof. Prints out internal objects represented as +@code{#<...>} as strings @code{"#<...>"} so that the format output can always +be processed by @code{read}. +@refill +@item @code{~:A} +Print out readproof. Prints out internal objects represented as +@code{#<...>} as strings @code{"#<...>"} so that the format output can always +be processed by @code{read}. +@item @code{~Q} +Prints information and a copyright notice on the format implementation. +@table @asis +@item @code{~:Q} +prints format version. +@end table +@refill +@item @code{~F, ~E, ~G, ~$} +may also print number strings, i.e. passing a number as a string and +format it accordingly. +@end table + +@subsubsection Configuration Variables + +Format has some configuration variables at the beginning of +@file{format.scm} to suit the systems and users needs. There should be +no modification necessary for the configuration that comes with SLIB. +If modification is desired the variable should be set after the format +code is loaded. Format detects automatically if the running scheme +system implements floating point numbers and complex numbers. + +@table @asis + +@item @var{format:symbol-case-conv} +Symbols are converted by @code{symbol->string} so the case type of the +printed symbols is implementation dependent. +@code{format:symbol-case-conv} is a one arg closure which is either +@code{#f} (no conversion), @code{string-upcase}, @code{string-downcase} +or @code{string-capitalize}. (default @code{#f}) + +@item @var{format:iobj-case-conv} +As @var{format:symbol-case-conv} but applies for the representation of +implementation internal objects. (default @code{#f}) + +@item @var{format:expch} +The character prefixing the exponent value in @code{~E} printing. (default +@code{#\E}) + +@end table + +@subsubsection Compatibility With Other Format Implementations + +@table @asis +@item SLIB format 2.x: +See @file{format.doc}. + +@item SLIB format 1.4: +Downward compatible except for padding support and @code{~A}, @code{~S}, +@code{~P}, @code{~X} uppercase printing. SLIB format 1.4 uses C-style +@code{printf} padding support which is completely replaced by the CL +@code{format} padding style. + +@item MIT C-Scheme 7.1: +Downward compatible except for @code{~}, which is not documented +(ignores all characters inside the format string up to a newline +character). (7.1 implements @code{~a}, @code{~s}, +~@var{newline}, @code{~~}, @code{~%}, numerical and variable +parameters and @code{:/@@} modifiers in the CL sense).@refill + +@item Elk 1.5/2.0: +Downward compatible except for @code{~A} and @code{~S} which print in +uppercase. (Elk implements @code{~a}, @code{~s}, @code{~~}, and +@code{~%} (no directive parameters or modifiers)).@refill + +@item Scheme->C 01nov91: +Downward compatible except for an optional destination parameter: S2C +accepts a format call without a destination which returns a formatted +string. This is equivalent to a #f destination in S2C. (S2C implements +@code{~a}, @code{~s}, @code{~c}, @code{~%}, and @code{~~} (no directive +parameters or modifiers)).@refill + +@end table + +This implementation of format is solely useful in the SLIB context +because it requires other components provided by SLIB.@refill + + +@node Standard Formatted I/O, Program Arguments, Format, Textual Conversion Packages +@section Standard Formatted I/O + +@menu +* Standard Formatted Output:: 'printf +* Standard Formatted Input:: 'scanf +@end menu + +@subsection stdio + +@code{(require 'stdio)} +@ftindex stdio + +@code{require}s @code{printf} and @code{scanf} and additionally defines +the symbols: + +@defvar stdin +Defined to be @code{(current-input-port)}. +@end defvar +@defvar stdout +Defined to be @code{(current-output-port)}. +@end defvar +@defvar stderr +Defined to be @code{(current-error-port)}. +@end defvar + + +@node Standard Formatted Output, Standard Formatted Input, Standard Formatted I/O, Standard Formatted I/O +@subsection Standard Formatted Output + +@code{(require 'printf)} +@ftindex printf + +@deffn Procedure printf format arg1 @dots{} +@deffnx Procedure fprintf port format arg1 @dots{} +@deffnx Procedure sprintf str format arg1 @dots{} + +Each function converts, formats, and outputs its @var{arg1} @dots{} +arguments according to the control string @var{format} argument and +returns the number of characters output. + +@code{printf} sends its output to the port @code{(current-output-port)}. +@code{fprintf} sends its output to the port @var{port}. @code{sprintf} +@code{string-set!}s locations of the non-constant string argument +@var{str} to the output characters. + +@quotation +@emph{Note:} sprintf should be changed to a macro so a @code{substring} +expression could be used for the @var{str} argument. +@end quotation + +The string @var{format} contains plain characters which are copied to +the output stream, and conversion specifications, each of which results +in fetching zero or more of the arguments @var{arg1} @dots{}. The +results are undefined if there are an insufficient number of arguments +for the format. If @var{format} is exhausted while some of the +@var{arg1} @dots{} arguments remain unused, the excess @var{arg1} +@dots{} arguments are ignored. + +The conversion specifications in a format string have the form: + +@example +% @r{[} @var{flags} @r{]} @r{[} @var{width} @r{]} @r{[} . @var{precision} @r{]} @r{[} @var{type} @r{]} @var{conversion} +@end example + +An output conversion specifications consist of an initial @samp{%} +character followed in sequence by: + +@itemize @bullet +@item +Zero or more @dfn{flag characters} that modify the normal behavior of +the conversion specification. + +@table @asis +@item @samp{-} +Left-justify the result in the field. Normally the result is +right-justified. + +@item @samp{+} +For the signed @samp{%d} and @samp{%i} conversions and all inexact +conversions, prefix a plus sign if the value is positive. + +@item @samp{ } +For the signed @samp{%d} and @samp{%i} conversions, if the result +doesn't start with a plus or minus sign, prefix it with a space +character instead. Since the @samp{+} flag ensures that the result +includes a sign, this flag is ignored if both are specified. + +@item @samp{#} +For inexact conversions, @samp{#} specifies that the result should +always include a decimal point, even if no digits follow it. For the +@samp{%g} and @samp{%G} conversions, this also forces trailing zeros +after the decimal point to be printed where they would otherwise be +elided. + +For the @samp{%o} conversion, force the leading digit to be @samp{0}, as +if by increasing the precision. For @samp{%x} or @samp{%X}, prefix a +leading @samp{0x} or @samp{0X} (respectively) to the result. This +doesn't do anything useful for the @samp{%d}, @samp{%i}, or @samp{%u} +conversions. Using this flag produces output which can be parsed by the +@code{scanf} functions with the @samp{%i} conversion (@pxref{Standard +Formatted Input}). + + +@item @samp{0} +Pad the field with zeros instead of spaces. The zeros are placed after +any indication of sign or base. This flag is ignored if the @samp{-} +flag is also specified, or if a precision is specified for an exact +converson. +@end table + +@item +An optional decimal integer specifying the @dfn{minimum field width}. +If the normal conversion produces fewer characters than this, the field +is padded (with spaces or zeros per the @samp{0} flag) to the specified +width. This is a @emph{minimum} width; if the normal conversion +produces more characters than this, the field is @emph{not} truncated. +@cindex minimum field width (@code{printf}) + +Alternatively, if the field width is @samp{*}, the next argument in the +argument list (before the actual value to be printed) is used as the +field width. The width value must be an integer. If the value is +negative it is as though the @samp{-} flag is set (see above) and the +absolute value is used as the field width. + +@item +An optional @dfn{precision} to specify the number of digits to be +written for numeric conversions and the maximum field width for string +conversions. The precision is specified by a period (@samp{.}) followed +optionally by a decimal integer (which defaults to zero if omitted). +@cindex precision (@code{printf}) + +Alternatively, if the precision is @samp{.*}, the next argument in the +argument list (before the actual value to be printed) is used as the +precision. The value must be an integer, and is ignored if negative. +If you specify @samp{*} for both the field width and precision, the +field width argument precedes the precision argument. The @samp{.*} +precision is an enhancement. C library versions may not accept this +syntax. + +For the @samp{%f}, @samp{%e}, and @samp{%E} conversions, the precision +specifies how many digits follow the decimal-point character. The +default precision is @code{6}. If the precision is explicitly @code{0}, +the decimal point character is suppressed. + +For the @samp{%g} and @samp{%G} conversions, the precision specifies how +many significant digits to print. Significant digits are the first +digit before the decimal point, and all the digits after it. If the +precision is @code{0} or not specified for @samp{%g} or @samp{%G}, it is +treated like a value of @code{1}. If the value being printed cannot be +expressed accurately in the specified number of digits, the value is +rounded to the nearest number that fits. + +For exact conversions, if a precision is supplied it specifies the +minimum number of digits to appear; leading zeros are produced if +necessary. If a precision is not supplied, the number is printed with +as many digits as necessary. Converting an exact @samp{0} with an +explicit precision of zero produces no characters. + @item -A new page is output. +An optional one of @samp{l}, @samp{h} or @samp{L}, which is ignored for +numeric conversions. It is an error to specify these modifiers for +non-numeric conversions. + @item -This entire process repeats until all the rows are output. +A character that specifies the conversion to be applied. +@end itemize + +@subsubsection Exact Conversions + +@table @asis +@item @samp{d}, @samp{i} +Print an integer as a signed decimal number. @samp{%d} and @samp{%i} +are synonymous for output, but are different when used with @code{scanf} +for input (@pxref{Standard Formatted Input}). + +@item @samp{o} +Print an integer as an unsigned octal number. + +@item @samp{u} +Print an integer as an unsigned decimal number. + +@item @samp{x}, @samp{X} +Print an integer as an unsigned hexadecimal number. @samp{%x} prints +using the digits @samp{0123456789abcdef}. @samp{%X} prints using the +digits @samp{0123456789ABCDEF}. +@end table + +@subsubsection Inexact Conversions +@emph{Note:} Inexact conversions are not supported yet. + +@table @asis +@item @samp{f} +Print a floating-point number in fixed-point notation. + +@item @samp{e}, @samp{E} +Print a floating-point number in exponential notation. @samp{%e} prints +@samp{e} between mantissa and exponont. @samp{%E} prints @samp{E} +between mantissa and exponont. + +@item @samp{g}, @samp{G} +Print a floating-point number in either normal or exponential notation, +whichever is more appropriate for its magnitude. @samp{%g} prints +@samp{e} between mantissa and exponont. @samp{%G} prints @samp{E} +between mantissa and exponont. +@end table + +@subsubsection Other Conversions +@table @asis +@item @samp{c} +Print a single character. The @samp{-} flag is the only one which can +be specified. It is an error to specify a precision. + +@item @samp{s} +Print a string. The @samp{-} flag is the only one which can be +specified. A precision specifies the maximum number of characters to +output; otherwise all characters in the string are output. + +@item @samp{a}, @samp{A} +Print a scheme expression. The @samp{-} flag left-justifies the output. +The @samp{#} flag specifies that strings and characters should be quoted +as by @code{write} (which can be read using @code{read}); otherwise, +output is as @code{display} prints. A precision specifies the maximum +number of characters to output; otherwise as many characters as needed +are output. + +@emph{Note:} @samp{%a} and @samp{%A} are SLIB extensions. + +@c @item @samp{p} +@c Print the value of a pointer. + +@c @item @samp{n} +@c Get the number of characters printed so far. @xref{Other Output Conversions}. +@c Note that this conversion specification never produces any output. + +@c @item @samp{m} +@c Print the string corresponding to the value of @code{errno}. +@c (This is a GNU extension.) +@c @xref{Other Output Conversions}. + +@item @samp{%} +Print a literal @samp{%} character. No argument is consumed. It is an +error to specifiy flags, field width, precision, or type modifiers with +@samp{%%}. +@end table +@end deffn + + +@node Standard Formatted Input, , Standard Formatted Output, Standard Formatted I/O +@subsection Standard Formatted Input + +@code{(require 'scanf)} +@ftindex scanf + +@deffn Function scanf-read-list format +@deffnx Function scanf-read-list format port +@deffnx Function scanf-read-list format string +@end deffn + +@defmac scanf format arg1 @dots{} +@defmacx fscanf port format arg1 @dots{} +@defmacx sscanf str format arg1 @dots{} + +Each function reads characters, interpreting them according to the +control string @var{format} argument. + +@code{scanf-read-list} returns a list of the items specified as far as +the input matches @var{format}. @code{scanf}, @code{fscanf}, and +@code{sscanf} return the number of items successfully matched and +stored. @code{scanf}, @code{fscanf}, and @code{sscanf} also set the +location corresponding to @var{arg1} @dots{} using the methods: + +@table @asis +@item symbol +@code{set!} +@item car expression +@code{set-car!} +@item cdr expression +@code{set-cdr!} +@item vector-ref expression +@code{vector-set!} +@item substring expression +@code{substring-move-left!} +@end table + +The argument to a @code{substring} expression in @var{arg1} @dots{} must +be a non-constant string. Characters will be stored starting at the +position specified by the second argument to @code{substring}. The +number of characters stored will be limited by either the position +specified by the third argument to @code{substring} or the length of the +matched string, whichever is less. + +The control string, @var{format}, contains conversion specifications and +other characters used to direct interpretation of input sequences. The +control string contains: + +@itemize @bullet +@item White-space characters (blanks, tabs, newlines, or formfeeds) +that cause input to be read (and discarded) up to the next +non-white-space character. + +@item An ordinary character (not @samp{%}) that must match the next +character of the input stream. + +@item Conversion specifications, consisting of the character @samp{%}, an +optional assignment suppressing character @samp{*}, an optional +numerical maximum-field width, an optional @samp{l}, @samp{h} or +@samp{L} which is ignored, and a conversion code. + +@c @item The conversion specification can alternatively be prefixed by +@c the character sequence @samp{%n$} instead of the character @samp{%}, +@c where @var{n} is a decimal integer in the range. The @samp{%n$} +@c construction indicates that the value of the next input field should be +@c placed in the @var{n}th place in the return list, rather than to the next +@c unused one. The two forms of introducing a conversion specification, +@c @samp{%} and @samp{%n$}, must not be mixed within a single format string +@c with the following exception: Skip fields (see below) can be designated +@c as @samp{%*} or @samp{%n$*}. In the latter case, @var{n} is ignored. + @end itemize -@end deffn -@noindent -The following example shows a new database with the name of -@file{foo.db} being created with tables describing processor families -and processor/os/compiler combinations. +Unless the specification contains the @samp{n} conversion character +(described below), a conversion specification directs the conversion of +the next input field. The result of a conversion specification is +returned in the position of the corresponding argument points, unless +@samp{*} indicates assignment suppression. Assignment suppression +provides a way to describe an input field to be skipped. An input field +is defined as a string of characters; it extends to the next +inappropriate character or until the field width, if specified, is +exhausted. -@noindent -The database command @code{define-tables} is defined to call -@code{define-tables} with its arguments. The database is also -configured to print @samp{Welcome} when the database is opened. The -database is then closed and reopened. +@quotation +@emph{Note:} This specification of format strings differs from the +@cite{ANSI C} and @cite{POSIX} specifications. In SLIB, white space +before an input field is not skipped unless white space appears before +the conversion specification in the format string. In order to write +format strings which work identically with @cite{ANSI C} and SLIB, +prepend whitespace to all conversion specifications except @samp{[} and +@samp{c}. +@end quotation -@example -(require 'database-utilities) -(define my-rdb (create-database "foo.db" 'alist-table)) +The conversion code indicates the interpretation of the input field; For +a suppressed field, no value is returned. The following conversion +codes are legal: -(define-tables my-rdb - '(*commands* - ((name symbol)) - ((parameters parameter-list) - (procedure expression) - (documentation string)) - ((define-tables - no-parameters - no-parameter-names - (lambda (rdb) (lambda specs (apply define-tables rdb specs))) - "Create or Augment tables from list of specs") - (*initialize* - no-parameters - no-parameter-names - (lambda (rdb) (display "Welcome") (newline) rdb) - "Print Welcome")))) +@table @asis -((my-rdb 'define-tables) - '(processor-family - ((family atom)) - ((also-ran processor-family)) - ((m68000 #f) - (m68030 m68000) - (i386 8086) - (8086 #f) - (powerpc #f))) +@item @samp{%} +A single % is expected in the input at this point; no value is returned. - '(platform - ((name symbol)) - ((processor processor-family) - (os symbol) - (compiler symbol)) - ((aix powerpc aix -) - (amiga-dice-c m68000 amiga dice-c) - (amiga-aztec m68000 amiga aztec) - (amiga-sas/c-5.10 m68000 amiga sas/c) - (atari-st-gcc m68000 atari gcc) - (atari-st-turbo-c m68000 atari turbo-c) - (borland-c-3.1 8086 ms-dos borland-c) - (djgpp i386 ms-dos gcc) - (linux i386 linux gcc) - (microsoft-c 8086 ms-dos microsoft-c) - (os/2-emx i386 os/2 gcc) - (turbo-c-2 8086 ms-dos turbo-c) - (watcom-9.0 i386 ms-dos watcom)))) +@item @samp{d}, @samp{D} +A decimal integer is expected. -((my-rdb 'close-database)) +@item @samp{u}, @samp{U} +An unsigned decimal integer is expected. -(set! my-rdb (open-database "foo.db" 'alist-table)) -@print{} -Welcome -@end example +@item @samp{o}, @samp{O} +An octal integer is expected. -@node Weight-Balanced Trees, Structures, Relational Database, Data Structures -@section Weight-Balanced Trees +@item @samp{x}, @samp{X} +A hexadecimal integer is expected. -@code{(require 'wt-tree)} +@item @samp{i} +An integer is expected. Returns the value of the next input item, +interpreted according to C conventions; a leading @samp{0} implies +octal, a leading @samp{0x} implies hexadecimal; otherwise, decimal is +assumed. -@cindex trees, balanced binary -@cindex balanced binary trees -@cindex binary trees -@cindex weight-balanced binary trees -Balanced binary trees are a useful data structure for maintaining large -sets of ordered objects or sets of associations whose keys are ordered. -MIT Scheme has an comprehensive implementation of weight-balanced binary -trees which has several advantages over the other data structures for -large aggregates: +@item @samp{n} +Returns the total number of bytes (including white space) read by +@code{scanf}. No input is consumed by @code{%n}. -@itemize @bullet -@item -In addition to the usual element-level operations like insertion, -deletion and lookup, there is a full complement of collection-level -operations, like set intersection, set union and subset test, all of -which are implemented with good orders of growth in time and space. -This makes weight balanced trees ideal for rapid prototyping of -functionally derived specifications. +@item @samp{f}, @samp{F}, @samp{e}, @samp{E}, @samp{g}, @samp{G} +A floating-point number is expected. The input format for +floating-point numbers is an optionally signed string of digits, +possibly containing a radix character @samp{.}, followed by an optional +exponent field consisting of an @samp{E} or an @samp{e}, followed by an +optional @samp{+}, @samp{-}, or space, followed by an integer. -@item -An element in a tree may be indexed by its position under the ordering -of the keys, and the ordinal position of an element may be determined, -both with reasonable efficiency. +@item @samp{c}, @samp{C} +@var{Width} characters are expected. The normal skip-over-white-space +is suppressed in this case; to read the next non-space character, use +@samp{%1s}. If a field width is given, a string is returned; up to the +indicated number of characters is read. -@item -Operations to find and remove minimum element make weight balanced trees -simple to use for priority queues. +@item @samp{s}, @samp{S} +A character string is expected The input field is terminated by a +white-space character. @code{scanf} cannot read a null string. + +@item @samp{[} +Indicates string data and the normal skip-over-leading-white-space is +suppressed. The left bracket is followed by a set of characters, called +the scanset, and a right bracket; the input field is the maximal +sequence of input characters consisting entirely of characters in the +scanset. @samp{^}, when it appears as the first character in the +scanset, serves as a complement operator and redefines the scanset as +the set of all characters not contained in the remainder of the scanset +string. Construction of the scanset follows certain conventions. A +range of characters may be represented by the construct first-last, +enabling @samp{[0123456789]} to be expressed @samp{[0-9]}. Using this +convention, first must be lexically less than or equal to last; +otherwise, the dash stands for itself. The dash also stands for itself +when it is the first or the last character in the scanset. To include +the right square bracket as an element of the scanset, it must appear as +the first character (possibly preceded by a @samp{^}) of the scanset, in +which case it will not be interpreted syntactically as the closing +bracket. At least one character must match for this conversion to +succeed. +@end table + +The @code{scanf} functions terminate their conversions at end-of-file, +at the end of the control string, or when an input character conflicts +with the control string. In the latter case, the offending character is +left unread in the input stream. +@end defmac + + +@node Program Arguments, Printing Scheme, Standard Formatted I/O, Textual Conversion Packages +@section Program Arguments + +@menu +* Getopt:: Command Line option parsing +* Command Line:: A command line reader for Scheme shells +* Parameter lists:: 'parameters +* Batch:: 'batch +@end menu + +@node Getopt, Command Line, Program Arguments, Program Arguments +@subsection Getopt + +@code{(require 'getopt)} +@ftindex getopt + +This routine implements Posix command line argument parsing. Notice +that returning values through global variables means that @code{getopt} +is @emph{not} reentrant. + +@defvar *optind* +Is the index of the current element of the command line. It is +initially one. In order to parse a new command line or reparse an old +one, @var{*opting*} must be reset. +@end defvar + +@defvar *optarg* +Is set by getopt to the (string) option-argument of the current option. +@end defvar + +@deffn Procedure getopt argc argv optstring +Returns the next option letter in @var{argv} (starting from +@code{(vector-ref argv *optind*)}) that matches a letter in +@var{optstring}. @var{argv} is a vector or list of strings, the 0th of +which getopt usually ignores. @var{argc} is the argument count, usually +the length of @var{argv}. @var{optstring} is a string of recognized +option characters; if a character is followed by a colon, the option +takes an argument which may be immediately following it in the string or +in the next element of @var{argv}. + +@var{*optind*} is the index of the next element of the @var{argv} vector +to be processed. It is initialized to 1 by @file{getopt.scm}, and +@code{getopt} updates it when it finishes with each element of +@var{argv}. + +@code{getopt} returns the next option character from @var{argv} that +matches a character in @var{optstring}, if there is one that matches. +If the option takes an argument, @code{getopt} sets the variable +@var{*optarg*} to the option-argument as follows: +@itemize @bullet @item -The implementation is @emph{functional} rather than @emph{imperative}. -This means that operations like `inserting' an association in a tree do -not destroy the old tree, in much the same way that @code{(+ 1 x)} -modifies neither the constant 1 nor the value bound to @code{x}. The -trees are referentially transparent thus the programmer need not worry -about copying the trees. Referential transparency allows space -efficiency to be achieved by sharing subtrees. +If the option was the last character in the string pointed to by an +element of @var{argv}, then @var{*optarg*} contains the next element of +@var{argv}, and @var{*optind*} is incremented by 2. If the resulting +value of @var{*optind*} is greater than or equal to @var{argc}, this +indicates a missing option argument, and @code{getopt} returns an error +indication. +@item +Otherwise, @var{*optarg*} is set to the string following the option +character in that element of @var{argv}, and @var{*optind*} is +incremented by 1. @end itemize -These features make weight-balanced trees suitable for a wide range of -applications, especially those that -require large numbers of sets or discrete maps. Applications that have -a few global databases and/or concentrate on element-level operations like -insertion and lookup are probably better off using hash-tables or -red-black trees. +If, when @code{getopt} is called, the string @code{(vector-ref argv +*optind*)} either does not begin with the character @code{#\-} or is +just @code{"-"}, @code{getopt} returns @code{#f} without changing +@var{*optind*}. If @code{(vector-ref argv *optind*)} is the string +@code{"--"}, @code{getopt} returns @code{#f} after incrementing +@var{*optind*}. + +If @code{getopt} encounters an option character that is not contained in +@var{optstring}, it returns the question-mark @code{#\?} character. If +it detects a missing option argument, it returns the colon character +@code{#\:} if the first character of @var{optstring} was a colon, or a +question-mark character otherwise. In either case, @code{getopt} sets +the variable @var{getopt:opt} to the option character that caused the +error. -The @emph{size} of a tree is the number of associations that it -contains. Weight balanced binary trees are balanced to keep the sizes -of the subtrees of each node within a constant factor of each other. -This ensures logarithmic times for single-path operations (like lookup -and insertion). A weight balanced tree takes space that is proportional -to the number of associations in the tree. For the current -implementation, the constant of proportionality is six words per -association. +The special option @code{"--"} can be used to delimit the end of the +options; @code{#f} is returned, and @code{"--"} is skipped. -@cindex binary trees, as sets -@cindex binary trees, as discrete maps -@cindex sets, using binary trees -@cindex discrete maps, using binary trees -Weight balanced trees can be used as an implementation for either -discrete sets or discrete maps (associations). Sets are implemented by -ignoring the datum that is associated with the key. Under this scheme -if an associations exists in the tree this indicates that the key of the -association is a member of the set. Typically a value such as -@code{()}, @code{#t} or @code{#f} is associated with the key. +RETURN VALUE -Many operations can be viewed as computing a result that, depending on -whether the tree arguments are thought of as sets or maps, is known by -two different names. -An example is @code{wt-tree/member?}, which, when -regarding the tree argument as a set, computes the set membership operation, but, -when regarding the tree as a discrete map, @code{wt-tree/member?} is the -predicate testing if the map is defined at an element in its domain. -Most names in this package have been chosen based on interpreting the -trees as sets, hence the name @code{wt-tree/member?} rather than -@code{wt-tree/defined-at?}. +@code{getopt} returns the next option character specified on the command +line. A colon @code{#\:} is returned if @code{getopt} detects a missing argument +and the first character of @var{optstring} was a colon @code{#\:}. +A question-mark @code{#\?} is returned if @code{getopt} encounters an option +character not in @var{optstring} or detects a missing argument and the first +character of @var{optstring} was not a colon @code{#\:}. -@cindex run-time-loadable option -@cindex option, run-time-loadable -The weight balanced tree implementation is a run-time-loadable option. -To use weight balanced trees, execute +Otherwise, @code{getopt} returns @code{#f} when all command line options have been +parsed. -@example -(load-option 'wt-tree) -@end example -@findex load-option +Example: +@lisp +#! /usr/local/bin/scm +;;;This code is SCM specific. +(define argv (program-arguments)) +(require 'getopt) +@ftindex getopt -@noindent -once before calling any of the procedures defined here. +(define opts ":a:b:cd") +(let loop ((opt (getopt (length argv) argv opts))) + (case opt + ((#\a) (print "option a: " *optarg*)) + ((#\b) (print "option b: " *optarg*)) + ((#\c) (print "option c")) + ((#\d) (print "option d")) + ((#\?) (print "error" getopt:opt)) + ((#\:) (print "missing arg" getopt:opt)) + ((#f) (if (< *optind* (length argv)) + (print "argv[" *optind* "]=" + (list-ref argv *optind*))) + (set! *optind* (+ *optind* 1)))) + (if (< *optind* (length argv)) + (loop (getopt (length argv) argv opts)))) +(slib:exit) +@end lisp +@end deffn -@menu -* Construction of Weight-Balanced Trees:: -* Basic Operations on Weight-Balanced Trees:: -* Advanced Operations on Weight-Balanced Trees:: -* Indexing Operations on Weight-Balanced Trees:: -@end menu +@subsection Getopt-- -@node Construction of Weight-Balanced Trees, Basic Operations on Weight-Balanced Trees, Weight-Balanced Trees, Weight-Balanced Trees -@subsection Construction of Weight-Balanced Trees +@defun getopt-- argc argv optstring +The procedure @code{getopt--} is an extended version of @code{getopt} +which parses @dfn{long option names} of the form +@samp{--hold-the-onions} and @samp{--verbosity-level=extreme}. +@w{@code{Getopt--}} behaves as @code{getopt} except for non-empty +options beginning with @samp{--}. -Binary trees require there to be a total order on the keys used to -arrange the elements in the tree. Weight balanced trees are organized -by @emph{types}, where the type is an object encapsulating the ordering -relation. Creating a tree is a two-stage process. First a tree type -must be created from the predicate which gives the ordering. The tree type -is then used for making trees, either empty or singleton trees or trees -from other aggregate structures like association lists. Once created, a -tree `knows' its type and the type is used to test compatibility between -trees in operations taking two trees. Usually a small number of tree -types are created at the beginning of a program and used many times -throughout the program's execution. +Options beginning with @samp{--} are returned as strings rather than +characters. If a value is assigned (using @samp{=}) to a long option, +@code{*optarg*} is set to the value. The @samp{=} and value are +not returned as part of the option string. -@deffn {procedure+} make-wt-tree-type keywt-tree tree-type alist -Returns a newly allocated weight-balanced tree that contains the same -associations as @var{alist}. This procedure is equivalent to: -@example -(lambda (type alist) - (let ((tree (make-wt-tree type))) - (for-each (lambda (association) - (wt-tree/add! tree - (car association) - (cdr association))) - alist) - tree)) -@end example -@end deffn +@node Parameter lists, Batch, Command Line, Program Arguments +@subsection Parameter lists +@code{(require 'parameters)} +@ftindex parameters -@node Basic Operations on Weight-Balanced Trees, Advanced Operations on Weight-Balanced Trees, Construction of Weight-Balanced Trees, Weight-Balanced Trees -@subsection Basic Operations on Weight-Balanced Trees +@noindent +Arguments to procedures in scheme are distinguished from each other by +their position in the procedure call. This can be confusing when a +procedure takes many arguments, many of which are not often used. + +@noindent +A @dfn{parameter-list} is a way of passing named information to a +procedure. Procedures are also defined to set unused parameters to +default values, check parameters, and combine parameter lists. + +@noindent +A @var{parameter} has the form @code{(@r{parameter-name} @r{value1} +@dots{})}. This format allows for more than one value per +parameter-name. -This section describes the basic tree operations on weight balanced -trees. These operations are the usual tree operations for insertion, -deletion and lookup, some predicates and a procedure for determining the -number of associations in a tree. +@noindent +A @var{parameter-list} is a list of @var{parameter}s, each with a +different @var{parameter-name}. -@deffn {procedure+} wt-tree? object -Returns @code{#t} if @var{object} is a weight-balanced tree, otherwise -returns @code{#f}. +@deffn Function make-parameter-list parameter-names +Returns an empty parameter-list with slots for @var{parameter-names}. @end deffn -@deffn {procedure+} wt-tree/empty? wt-tree -Returns @code{#t} if @var{wt-tree} contains no associations, otherwise -returns @code{#f}. +@deffn Function parameter-list-ref parameter-list parameter-name +@var{parameter-name} must name a valid slot of @var{parameter-list}. +@code{parameter-list-ref} returns the value of parameter +@var{parameter-name} of @var{parameter-list}. @end deffn -@deffn {procedure+} wt-tree/size wt-tree -Returns the number of associations in @var{wt-tree}, an exact -non-negative integer. This operation takes constant time. +@deffn Procedure adjoin-parameters! parameter-list parameter1 @dots{} +Returns @var{parameter-list} with @var{parameter1} @dots{} merged in. @end deffn +@deffn Procedure parameter-list-expand expanders parameter-list +@var{expanders} is a list of procedures whose order matches the order of +the @var{parameter-name}s in the call to @code{make-parameter-list} +which created @var{parameter-list}. For each non-false element of +@var{expanders} that procedure is mapped over the corresponding +parameter value and the returned parameter lists are merged into +@var{parameter-list}. -@deffn {procedure+} wt-tree/add wt-tree key datum -Returns a new tree containing all the associations in @var{wt-tree} and -the association of @var{datum} with @var{key}. If @var{wt-tree} already -had an association for @var{key}, the new association overrides the old. -The average and worst-case times required by this operation are -proportional to the logarithm of the number of associations in -@var{wt-tree}. +This process is repeated until @var{parameter-list} stops growing. The +value returned from @code{parameter-list-expand} is unspecified. @end deffn -@deffn {procedure+} wt-tree/add! wt-tree key datum -Associates @var{datum} with @var{key} in @var{wt-tree} and returns an -unspecified value. If @var{wt-tree} already has an association for -@var{key}, that association is replaced. The average and worst-case -times required by this operation are proportional to the logarithm of -the number of associations in @var{wt-tree}. +@deffn Function fill-empty-parameters defaulters parameter-list +@var{defaulters} is a list of procedures whose order matches the order +of the @var{parameter-name}s in the call to @code{make-parameter-list} +which created @var{parameter-list}. @code{fill-empty-parameters} +returns a new parameter-list with each empty parameter replaced with the +list returned by calling the corresponding @var{defaulter} with +@var{parameter-list} as its argument. @end deffn -@deffn {procedure+} wt-tree/member? key wt-tree -Returns @code{#t} if @var{wt-tree} contains an association for -@var{key}, otherwise returns @code{#f}. The average and worst-case -times required by this operation are proportional to the logarithm of -the number of associations in @var{wt-tree}. +@deffn Function check-parameters checks parameter-list +@var{checks} is a list of procedures whose order matches the order of +the @var{parameter-name}s in the call to @code{make-parameter-list} +which created @var{parameter-list}. + +@code{check-parameters} returns @var{parameter-list} if each @var{check} +of the corresponding @var{parameter-list} returns non-false. If some +@var{check} returns @code{#f} an error is signaled. @end deffn -@deffn {procedure+} wt-tree/lookup wt-tree key default -Returns the datum associated with @var{key} in @var{wt-tree}. If -@var{wt-tree} doesn't contain an association for @var{key}, -@var{default} is returned. The average and worst-case times required by -this operation are proportional to the logarithm of the number of -associations in @var{wt-tree}. +@noindent +In the following procedures @var{arities} is a list of symbols. The +elements of @code{arities} can be: + +@table @code +@item single +Requires a single parameter. +@item optional +A single parameter or no parameter is acceptable. +@item boolean +A single boolean parameter or zero parameters is acceptable. +@item nary +Any number of parameters are acceptable. +@item nary1 +One or more of parameters are acceptable. +@end table + +@deffn Function parameter-list->arglist positions arities types parameter-list +Returns @var{parameter-list} converted to an argument list. Parameters +of @var{arity} type @code{single} and @code{boolean} are converted to +the single value associated with them. The other @var{arity} types are +converted to lists of the value(s) of type @var{types}. + +@var{positions} is a list of positive integers whose order matches the +order of the @var{parameter-name}s in the call to +@code{make-parameter-list} which created @var{parameter-list}. The +integers specify in which argument position the corresponding parameter +should appear. @end deffn -@deffn {procedure+} wt-tree/delete wt-tree key -Returns a new tree containing all the associations in @var{wt-tree}, -except that if @var{wt-tree} contains an association for @var{key}, it -is removed from the result. The average and worst-case times required -by this operation are proportional to the logarithm of the number of -associations in @var{wt-tree}. +@deffn Function getopt->parameter-list argc argv optnames arities types aliases +Returns @var{argv} converted to a parameter-list. @var{optnames} are +the parameter-names. @var{aliases} is a list of lists of strings and +elements of @var{optnames}. Each of these strings which have length of +1 will be treated as a single @key{-} option by @code{getopt}. Longer +strings will be treated as long-named options (@pxref{Getopt, getopt--}). @end deffn -@deffn {procedure+} wt-tree/delete! wt-tree key -If @var{wt-tree} contains an association for @var{key} the association -is removed. Returns an unspecified value. The average and worst-case -times required by this operation are proportional to the logarithm of -the number of associations in @var{wt-tree}. +@deffn Function getopt->arglist argc argv optnames positions arities types defaulters checks aliases +Like @code{getopt->parameter-list}, but converts @var{argv} to an +argument-list as specified by @var{optnames}, @var{positions}, +@var{arities}, @var{types}, @var{defaulters}, @var{checks}, and +@var{aliases}. @end deffn +@noindent +These @code{getopt} functions can be used with SLIB relational +databases. For an example, @xref{Database Utilities, +make-command-server}. -@node Advanced Operations on Weight-Balanced Trees, Indexing Operations on Weight-Balanced Trees, Basic Operations on Weight-Balanced Trees, Weight-Balanced Trees -@subsection Advanced Operations on Weight-Balanced Trees +@noindent +If errors are encountered while processing options, directions for using +the options are printed to @code{current-error-port}. -In the following the @emph{size} of a tree is the number of associations -that the tree contains, and a @emph{smaller} tree contains fewer -associations. +@example +(begin + (set! *optind* 1) + (getopt->parameter-list + 2 + '("cmd" "-?") + '(flag number symbols symbols string flag2 flag3 num2 num3) + '(boolean optional nary1 nary single boolean boolean nary nary) + '(boolean integer symbol symbol string boolean boolean integer integer) + '(("flag" flag) + ("f" flag) + ("Flag" flag2) + ("B" flag3) + ("optional" number) + ("o" number) + ("nary1" symbols) + ("N" symbols) + ("nary" symbols) + ("n" symbols) + ("single" string) + ("s" string) + ("a" num2) + ("Abs" num3)))) +@print{} +Usage: cmd [OPTION ARGUMENT ...] ... + + -f, --flag + -o, --optional= + -n, --nary= ... + -N, --nary1= ... + -s, --single= + --Flag + -B + -a ... + --Abs= ... + +ERROR: getopt->parameter-list "unrecognized option" "-?" +@end example -@deffn {procedure+} wt-tree/split< wt-tree bound -Returns a new tree containing all and only the associations in -@var{wt-tree} which have a key that is less than @var{bound} in the -ordering relation of the tree type of @var{wt-tree}. The average and -worst-case times required by this operation are proportional to the -logarithm of the size of @var{wt-tree}. -@end deffn -@deffn {procedure+} wt-tree/split> wt-tree bound -Returns a new tree containing all and only the associations in -@var{wt-tree} which have a key that is greater than @var{bound} in the -ordering relation of the tree type of @var{wt-tree}. The average and -worst-case times required by this operation are proportional to the -logarithm of size of @var{wt-tree}. -@end deffn +@node Batch, , Parameter lists, Program Arguments +@subsection Batch -@deffn {procedure+} wt-tree/union wt-tree-1 wt-tree-2 -Returns a new tree containing all the associations from both trees. -This operation is asymmetric: when both trees have an association for -the same key, the returned tree associates the datum from @var{wt-tree-2} -with the key. Thus if the trees are viewed as discrete maps then -@code{wt-tree/union} computes the map override of @var{wt-tree-1} by -@var{wt-tree-2}. If the trees are viewed as sets the result is the set -union of the arguments. -The worst-case time required by this operation -is proportional to the sum of the sizes of both trees. -If the minimum key of one tree is greater than the maximum key of -the other tree then the time required is at worst proportional to -the logarithm of the size of the larger tree. -@end deffn +@code{(require 'batch)} +@ftindex batch -@deffn {procedure+} wt-tree/intersection wt-tree-1 wt-tree-2 -Returns a new tree containing all and only those associations from -@var{wt-tree-1} which have keys appearing as the key of an association -in @var{wt-tree-2}. Thus the associated data in the result are those -from @var{wt-tree-1}. If the trees are being used as sets the result is -the set intersection of the arguments. As a discrete map operation, -@code{wt-tree/intersection} computes the domain restriction of -@var{wt-tree-1} to (the domain of) @var{wt-tree-2}. -The time required by this operation is never worse that proportional to -the sum of the sizes of the trees. -@end deffn +@noindent +The batch procedures provide a way to write and execute portable scripts +for a variety of operating systems. Each @code{batch:} procedure takes +as its first argument a parameter-list (@pxref{Parameter lists}). This +parameter-list argument @var{parms} contains named associations. Batch +currently uses 2 of these: -@deffn {procedure+} wt-tree/difference wt-tree-1 wt-tree-2 -Returns a new tree containing all and only those associations from -@var{wt-tree-1} which have keys that @emph{do not} appear as the key of -an association in @var{wt-tree-2}. If the trees are viewed as sets the -result is the asymmetric set difference of the arguments. As a discrete -map operation, it computes the domain restriction of @var{wt-tree-1} to -the complement of (the domain of) @var{wt-tree-2}. -The time required by this operation is never worse that proportional to -the sum of the sizes of the trees. -@end deffn +@table @code +@item batch-port +The port on which to write lines of the batch file. +@item batch-dialect +The syntax of batch file to generate. Currently supported are: +@itemize @bullet +@item +unix +@item +dos +@item +vms +@item +system +@item +*unknown* +@end itemize +@end table +@noindent +@file{batch.scm} uses 2 enhanced relational tables (@pxref{Database +Utilities}) to store information linking the names of +@code{operating-system}s to @code{batch-dialect}es. -@deffn {procedure+} wt-tree/subset? wt-tree-1 wt-tree-2 -Returns @code{#t} iff the key of each association in @var{wt-tree-1} is -the key of some association in @var{wt-tree-2}, otherwise returns @code{#f}. -Viewed as a set operation, @code{wt-tree/subset?} is the improper subset -predicate. -A proper subset predicate can be constructed: +@defun batch:initialize! database +Defines @code{operating-system} and @code{batch-dialect} tables and adds +the domain @code{operating-system} to the enhanced relational database +@var{database}. +@end defun -@example -(define (proper-subset? s1 s2) - (and (wt-tree/subset? s1 s2) - (< (wt-tree/size s1) (wt-tree/size s2)))) -@end example +@defvar batch:platform +Is batch's best guess as to which operating-system it is running under. +@code{batch:platform} is set to @code{(software-type)} +(@pxref{Configuration}) unless @code{(software-type)} is @code{unix}, +in which case finer distinctions are made. +@end defvar + +@defun batch:call-with-output-script parms file proc +@var{proc} should be a procedure of one argument. If @var{file} is an +output-port, @code{batch:call-with-output-script} writes an appropriate +header to @var{file} and then calls @var{proc} with @var{file} as the +only argument. If @var{file} is a string, +@code{batch:call-with-output-script} opens a output-file of name +@var{file}, writes an appropriate header to @var{file}, and then calls +@var{proc} with the newly opened port as the only argument. Otherwise, +@code{batch:call-with-output-script} acts as if it was called with the +result of @code{(current-output-port)} as its third argument. +@end defun + +@defun batch:apply-chop-to-fit proc arg1 arg2 @dots{} list +The procedure @var{proc} must accept at least one argument and return +@code{#t} if successful, @code{#f} if not. +@code{batch:apply-chop-to-fit} calls @var{proc} with @var{arg1}, +@var{arg2}, @dots{}, and @var{chunk}, where @var{chunk} is a subset of +@var{list}. @code{batch:apply-chop-to-fit} tries @var{proc} with +successively smaller subsets of @var{list} until either @var{proc} +returns non-false, or the @var{chunk}s become empty. +@end defun + +@noindent +The rest of the @code{batch:} procedures write (or execute if +@code{batch-dialect} is @code{system}) commands to the batch port which +has been added to @var{parms} or @code{(copy-tree @var{parms})} by the +code: -As a discrete map operation, @code{wt-tree/subset?} is the subset -test on the domain(s) of the map(s). In the worst-case the time -required by this operation is proportional to the size of -@var{wt-tree-1}. -@end deffn +@example +(adjoin-parameters! @var{parms} (list 'batch-port @var{port})) +@end example +@defun batch:system parms string1 string2 @dots{} +Calls @code{batch:try-system} (below) with arguments, but signals an +error if @code{batch:try-system} returns @code{#f}. +@end defun -@deffn {procedure+} wt-tree/set-equal? wt-tree-1 wt-tree-2 -Returns @code{#t} iff for every association in @var{wt-tree-1} there is -an association in @var{wt-tree-2} that has the same key, and @emph{vice -versa}. +@noindent +These functions return a non-false value if the command was successfully +translated into the batch dialect and @code{#f} if not. In the case of +the @code{system} dialect, the value is non-false if the operation +suceeded. -Viewing the arguments as sets @code{wt-tree/set-equal?} is the set -equality predicate. As a map operation it determines if two maps are -defined on the same domain. +@defun batch:try-system parms string1 string2 @dots{} +Writes a command to the @code{batch-port} in @var{parms} which executes +the program named @var{string1} with arguments @var{string2} @dots{}. +@end defun -This procedure is equivalent to +@defun batch:run-script parms string1 string2 @dots{} +Writes a command to the @code{batch-port} in @var{parms} which executes +the batch script named @var{string1} with arguments @var{string2} +@dots{}. -@example -(lambda (wt-tree-1 wt-tree-2) - (and (wt-tree/subset? wt-tree-1 wt-tree-2 - (wt-tree/subset? wt-tree-2 wt-tree-1))) -@end example +@emph{Note:} @code{batch:run-script} and @code{batch:try-system} are not the +same for some operating systems (VMS). +@end defun -In the worst-case the time required by this operation is proportional to -the size of the smaller tree. -@end deffn +@defun batch:comment parms line1 @dots{} +Writes comment lines @var{line1} @dots{} to the @code{batch-port} in +@var{parms}. +@end defun +@defun batch:lines->file parms file line1 @dots{} +Writes commands to the @code{batch-port} in @var{parms} which create a +file named @var{file} with contents @var{line1} @dots{}. +@end defun -@deffn {procedure+} wt-tree/fold combiner initial wt-tree -This procedure reduces @var{wt-tree} by combining all the associations, -using an reverse in-order traversal, so the associations are visited in -reverse order. @var{Combiner} is a procedure of three arguments: a key, -a datum and the accumulated result so far. Provided @var{combiner} -takes time bounded by a constant, @code{wt-tree/fold} takes time -proportional to the size of @var{wt-tree}. +@defun batch:delete-file parms file +Writes a command to the @code{batch-port} in @var{parms} which deletes +the file named @var{file}. +@end defun -A sorted association list can be derived simply: +@defun batch:rename-file parms old-name new-name +Writes a command to the @code{batch-port} in @var{parms} which renames +the file @var{old-name} to @var{new-name}. +@end defun -@example -(wt-tree/fold (lambda (key datum list) - (cons (cons key datum) list)) - '() - @var{wt-tree})) -@end example +@noindent +In addition, batch provides some small utilities very useful for writing +scripts: -The data in the associations can be summed like this: +@defun truncate-up-to path char +@defunx truncate-up-to path string +@defunx truncate-up-to path charlist +@var{path} can be a string or a list of strings. Returns @var{path} +sans any prefixes ending with a character of the second argument. This +can be used to derive a filename moved locally from elsewhere. @example -(wt-tree/fold (lambda (key datum sum) (+ sum datum)) - 0 - @var{wt-tree}) +(truncate-up-to "/usr/local/lib/slib/batch.scm" "/") +@result{} "batch.scm" @end example -@end deffn +@end defun -@deffn {procedure+} wt-tree/for-each action wt-tree -This procedure traverses the tree in-order, applying @var{action} to -each association. -The associations are processed in increasing order of their keys. -@var{Action} is a procedure of two arguments which take the key and -datum respectively of the association. -Provided @var{action} takes time bounded by a constant, -@code{wt-tree/for-each} takes time proportional to in the size of -@var{wt-tree}. -The example prints the tree: +@defun replace-suffix str old new +@var{str} can be a string or a list of strings. Returns a new string +(or strings) similar to @code{str} but with the suffix string @var{old} +removed and the suffix string @var{new} appended. If the end of +@var{str} does not match @var{old}, an error is signaled. @example -(wt-tree/for-each (lambda (key value) - (display (list key value))) - @var{wt-tree})) +(replace-suffix "/usr/local/lib/slib/batch.scm" ".scm" ".c") +@result{} "/usr/local/lib/slib/batch.c" @end example -@end deffn - +@end defun -@node Indexing Operations on Weight-Balanced Trees, , Advanced Operations on Weight-Balanced Trees, Weight-Balanced Trees -@subsection Indexing Operations on Weight-Balanced Trees +@defun string-join joiner string1 @dots{} +Returns a new string consisting of all the strings @var{string1} @dots{} +in order appended together with the string @var{joiner} between each +adjacent pair. +@end defun -Weight balanced trees support operations that view the tree as sorted -sequence of associations. Elements of the sequence can be accessed by -position, and the position of an element in the sequence can be -determined, both in logarthmic time. +@defun must-be-first list1 list2 +Returns a new list consisting of the elements of @var{list2} ordered so +that if some elements of @var{list1} are @code{equal?} to elements of +@var{list2}, then those elements will appear first and in the order of +@var{list1}. +@end defun -@deffn {procedure+} wt-tree/index wt-tree index -@deffnx {procedure+} wt-tree/index-datum wt-tree index -@deffnx {procedure+} wt-tree/index-pair wt-tree index -Returns the 0-based @var{index}th association of @var{wt-tree} in the -sorted sequence under the tree's ordering relation on the keys. -@code{wt-tree/index} returns the @var{index}th key, -@code{wt-tree/index-datum} returns the datum associated with the -@var{index}th key and @code{wt-tree/index-pair} returns a new pair -@code{(@var{key} . @var{datum})} which is the @code{cons} of the @var{index}th -key and its datum. The average and worst-case times required by this -operation are proportional to the logarithm of the number of -associations in the tree. +@defun must-be-last list1 list2 +Returns a new list consisting of the elements of @var{list1} ordered so +that if some elements of @var{list2} are @code{equal?} to elements of +@var{list1}, then those elements will appear last and in the order of +@var{list2}. +@end defun -These operations signal an error if the tree is empty, if -@var{index}@code{<0}, or if @var{index} is greater than or equal to the -number of associations in the tree. +@defun os->batch-dialect osname +Returns its best guess for the @code{batch-dialect} to be used for the +operating-system named @var{osname}. @code{os->batch-dialect} uses the +tables added to @var{database} by @code{batch:initialize!}. +@end defun -Indexing can be used to find the median and maximum keys in the tree as -follows: +@noindent +Here is an example of the use of most of batch's procedures: @example -median: (wt-tree/index @var{wt-tree} (quotient (wt-tree/size @var{wt-tree}) 2)) +(require 'database-utilities) +@ftindex database-utilities +(require 'parameters) +@ftindex parameters +(require 'batch) +@ftindex batch -maximum: (wt-tree/index @var{wt-tree} (-1+ (wt-tree/size @var{wt-tree}))) +(define batch (create-database #f 'alist-table)) +(batch:initialize! batch) + +(define my-parameters + (list (list 'batch-dialect (os->batch-dialect batch:platform)) + (list 'platform batch:platform) + (list 'batch-port (current-output-port)))) ;gets filled in later + +(batch:call-with-output-script + my-parameters + "my-batch" + (lambda (batch-port) + (adjoin-parameters! my-parameters (list 'batch-port batch-port)) + (and + (batch:comment my-parameters + "================ Write file with C program.") + (batch:rename-file my-parameters "hello.c" "hello.c~") + (batch:lines->file my-parameters "hello.c" + "#include " + "int main(int argc, char **argv)" + "@{" + " printf(\"hello world\\n\");" + " return 0;" + "@}" ) + (batch:system my-parameters "cc" "-c" "hello.c") + (batch:system my-parameters "cc" "-o" "hello" + (replace-suffix "hello.c" ".c" ".o")) + (batch:system my-parameters "hello") + (batch:delete-file my-parameters "hello") + (batch:delete-file my-parameters "hello.c") + (batch:delete-file my-parameters "hello.o") + (batch:delete-file my-parameters "my-batch") + ))) @end example -@end deffn -@deffn {procedure+} wt-tree/rank wt-tree key -Determines the 0-based position of @var{key} in the sorted sequence of -the keys under the tree's ordering relation, or @code{#f} if the tree -has no association with for @var{key}. This procedure returns either an -exact non-negative integer or @code{#f}. The average and worst-case -times required by this operation are proportional to the logarithm of -the number of associations in the tree. -@end deffn +@noindent +Produces the file @file{my-batch}: -@deffn {procedure+} wt-tree/min wt-tree -@deffnx {procedure+} wt-tree/min-datum wt-tree -@deffnx {procedure+} wt-tree/min-pair wt-tree -Returns the association of @var{wt-tree} that has the least key under the tree's ordering relation. -@code{wt-tree/min} returns the least key, -@code{wt-tree/min-datum} returns the datum associated with the -least key and @code{wt-tree/min-pair} returns a new pair -@code{(key . datum)} which is the @code{cons} of the minimum key and its datum. -The average and worst-case times required by this operation are -proportional to the logarithm of the number of associations in the tree. +@example +#!/bin/sh +# "my-batch" build script created Sat Jun 10 21:20:37 1995 +# ================ Write file with C program. +mv -f hello.c hello.c~ +rm -f hello.c +echo '#include '>>hello.c +echo 'int main(int argc, char **argv)'>>hello.c +echo '@{'>>hello.c +echo ' printf("hello world\n");'>>hello.c +echo ' return 0;'>>hello.c +echo '@}'>>hello.c +cc -c hello.c +cc -o hello hello.o +hello +rm -f hello +rm -f hello.c +rm -f hello.o +rm -f my-batch +@end example + +@noindent +When run, @file{my-batch} prints: -These operations signal an error if the tree is empty. -They could be written @example -(define (wt-tree/min tree) (wt-tree/index tree 0)) -(define (wt-tree/min-datum tree) (wt-tree/index-datum tree 0)) -(define (wt-tree/min-pair tree) (wt-tree/index-pair tree 0)) +bash$ my-batch +mv: hello.c: No such file or directory +hello world @end example -@end deffn -@deffn {procedure+} wt-tree/delete-min wt-tree -Returns a new tree containing all of the associations in @var{wt-tree} -except the association with the least key under the @var{wt-tree}'s -ordering relation. An error is signalled if the tree is empty. The -average and worst-case times required by this operation are proportional -to the logarithm of the number of associations in the tree. This -operation is equivalent to -@example -(wt-tree/delete @var{wt-tree} (wt-tree/min @var{wt-tree})) -@end example -@end deffn +@node Printing Scheme, Time and Date, Program Arguments, Textual Conversion Packages +@section Printing Scheme + +@menu +* Generic-Write:: 'generic-write +* Object-To-String:: 'object->string +* Pretty-Print:: 'pretty-print, 'pprint-file +@end menu + + +@node Generic-Write, Object-To-String, Printing Scheme, Printing Scheme +@subsection Generic-Write + +@code{(require 'generic-write)} +@ftindex generic-write + +@code{generic-write} is a procedure that transforms a Scheme data value +(or Scheme program expression) into its textual representation and +prints it. The interface to the procedure is sufficiently general to +easily implement other useful formatting procedures such as pretty +printing, output to a string and truncated output.@refill +@deffn Procedure generic-write obj display? width output +@table @var +@item obj +Scheme data value to transform. +@item display? +Boolean, controls whether characters and strings are quoted. +@item width +Extended boolean, selects format: +@table @asis +@item #f +single line format +@item integer > 0 +pretty-print (value = max nb of chars per line) +@end table +@item output +Procedure of 1 argument of string type, called repeatedly with +successive substrings of the textual representation. This procedure can +return @code{#f} to stop the transformation. +@end table -@deffn {procedure+} wt-tree/delete-min! wt-tree -Removes the association with the least key under the @var{wt-tree}'s -ordering relation. An error is signalled if the tree is empty. The -average and worst-case times required by this operation are proportional -to the logarithm of the number of associations in the tree. This -operation is equivalent to +The value returned by @code{generic-write} is undefined. -@example -(wt-tree/delete! @var{wt-tree} (wt-tree/min @var{wt-tree})) -@end example +Examples: +@lisp +(write obj) @equiv{} (generic-write obj #f #f @var{display-string}) +(display obj) @equiv{} (generic-write obj #t #f @var{display-string}) +@end lisp +@noindent +where +@lisp +@var{display-string} @equiv{} +(lambda (s) (for-each write-char (string->list s)) #t) +@end lisp @end deffn -@node Structures, , Weight-Balanced Trees, Data Structures -@section Structures +@node Object-To-String, Pretty-Print, Generic-Write, Printing Scheme +@subsection Object-To-String -@code{(require 'struct)} (uses defmacros) +@code{(require 'object->string)} +@ftindex object->string -@code{defmacro}s which implement @dfn{records} from the book -@cite{Essentials of Programming Languages} by Daniel P. Friedman, M. -Wand and C.T. Haynes. Copyright 1992 Jeff Alexander, Shinnder Lee, and -Lewis Patterson@refill +@defun object->string obj +Returns the textual representation of @var{obj} as a string. +@end defun -Matthew McDonald added field setters. -@defmac define-record tag (var1 var2 @dots{}) -Defines several functions pertaining to record-name @var{tag}: -@defun make-@var{tag} var1 var2 @dots{} -@end defun -@defun @var{tag}? obj -@end defun -@defun @var{tag}->var1 obj -@end defun -@defun @var{tag}->var2 obj -@end defun -@dots{} -@defun set-@var{@var{tag}}-var1! obj val -@end defun -@defun set-@var{@var{tag}}-var2! obj val -@end defun -@dots{} -Here is an example of its use. +@node Pretty-Print, , Object-To-String, Printing Scheme +@subsection Pretty-Print -@example -(define-record term (operator left right)) -@result{} # -(define foo (make-term 'plus 1 2)) -@result{} foo -(term-left foo) -@result{} 1 -(set-term-left! foo 2345) -@result{} # -(term-left foo) -@result{} 2345 -@end example -@end defmac +@code{(require 'pretty-print)} +@ftindex pretty-print -@defmac variant-case exp (tag (var1 var2 @dots{}) body) @dots{} -executes the following for the matching clause: +@deffn Procedure pretty-print obj +@deffnx Procedure pretty-print obj port + +@code{pretty-print}s @var{obj} on @var{port}. If @var{port} is not +specified, @code{current-output-port} is used. +Example: @example -((lambda (@var{var1} @var{var} @dots{}) @var{body}) - (@var{tag->var1} @var{exp}) - (@var{tag->var2} @var{exp}) @dots{}) +@group +(pretty-print '((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) + (16 17 18 19 20) (21 22 23 24 25))) + @print{} ((1 2 3 4 5) + @print{} (6 7 8 9 10) + @print{} (11 12 13 14 15) + @print{} (16 17 18 19 20) + @print{} (21 22 23 24 25)) +@end group @end example -@end defmac - -@node Macros, Numerics, Data Structures, Top -@chapter Macros -@menu -* Defmacro:: Supported by all implementations +@end deffn -* R4RS Macros:: 'macro -* Macro by Example:: 'macro-by-example -* Macros That Work:: 'macros-that-work -* Syntactic Closures:: 'syntactic-closures -* Syntax-Case Macros:: 'syntax-case -Syntax extensions (macros) included with SLIB. Also @xref{Structures}. +@code{(require 'pprint-file)} +@ftindex pprint-file -* Fluid-Let:: 'fluid-let -* Yasos:: 'yasos, 'oop, 'collect -@end menu +@deffn Procedure pprint-file infile +@deffnx Procedure pprint-file infile outfile +Pretty-prints all the code in @var{infile}. If @var{outfile} is +specified, the output goes to @var{outfile}, otherwise it goes to +@code{(current-output-port)}.@refill +@end deffn +@defun pprint-filter-file infile proc outfile +@defunx pprint-filter-file infile proc +@var{infile} is a port or a string naming an existing file. Scheme +source code expressions and definitions are read from the port (or file) +and @var{proc} is applied to them sequentially. -@node Defmacro, R4RS Macros, Macros, Macros -@section Defmacro +@var{outfile} is a port or a string. If no @var{outfile} is specified +then @code{current-output-port} is assumed. These expanded expressions +are then @code{pretty-print}ed to this port. -Defmacros are supported by all implementations. -@c See also @code{gentemp}, in @ref{Macros}. +Whitepsace and comments (introduced by @code{;}) which are not part of +scheme expressions are reproduced in the output. This procedure does +not affect the values returned by @code{current-input-port} and +@code{current-output-port}.@refill +@end defun -@defun gentemp -Returns a new (interned) symbol each time it is called. The symbol -names are implementation-dependent +@code{pprint-filter-file} can be used to pre-compile macro-expansion and +thus can reduce loading time. The following will write into +@file{exp-code.scm} the result of expanding all defmacros in +@file{code.scm}. @lisp -(gentemp) @result{} scm:G0 -(gentemp) @result{} scm:G1 +(require 'pprint-file) +@ftindex pprint-file +(require 'defmacroexpand) +@ftindex defmacroexpand +(defmacro:load "my-macros.scm") +(pprint-filter-file "code.scm" defmacro:expand* "exp-code.scm") @end lisp -@end defun -@defun defmacro:eval e -Returns the @code{slib:eval} of expanding all defmacros in scheme -expression @var{e}. -@end defun +@node Time and Date, Vector Graphics, Printing Scheme, Textual Conversion Packages +@section Time and Date -@defun defmacro:load filename -@var{filename} should be a string. If filename names an existing file, -the @code{defmacro:load} procedure reads Scheme source code expressions -and definitions from the file and evaluates them sequentially. These -source code expressions and definitions may contain defmacro -definitions. The @code{macro:load} procedure does not affect the values -returned by @code{current-input-port} and -@code{current-output-port}.@refill -@end defun +@menu +* Posix Time:: 'posix-time +* Common-Lisp Time:: 'common-lisp-time +@end menu -@defun defmacro? sym -Returns @code{#t} if @var{sym} has been defined by @code{defmacro}, -@code{#f} otherwise. -@end defun -@defun macroexpand-1 form -@defunx macroexpand form -If @var{form} is a macro call, @code{macroexpand-1} will expand the -macro call once and return it. A @var{form} is considered to be a macro -call only if it is a cons whose @code{car} is a symbol for which a -@code{defmacr} has been defined. +@node Posix Time, Common-Lisp Time, Time and Date, Time and Date +@subsection Posix Time -@code{macroexpand} is similar to @code{macroexpand-1}, but repeatedly -expands @var{form} until it is no longer a macro call. -@end defun +@example +(require 'posix-time) +@ftindex posix-time +@end example -@defmac defmacro name lambda-list form @dots{} -When encountered by @code{defmacro:eval}, @code{defmacro:macroexpand*}, -or @code{defmacro:load} defines a new macro which will henceforth be -expanded when encountered by @code{defmacro:eval}, -@code{defmacro:macroexpand*}, or @code{defmacro:load}. -@end defmac +@deftp {Data Type} {Calendar-Time} +@cindex calendar time +@cindex caltime +is a datatype encapsulating time. +@end deftp -@subsection Defmacroexpand -@code{(require 'defmacroexpand)} +@deftp {Data Type} {Coordinated Universal Time} +@cindex Coordinated Universal Time +@cindex UTC +(abbreviated @dfn{UTC}) is a vector of integers representing time: -@defun defmacro:expand* e -Returns the result of expanding all defmacros in scheme expression -@var{e}. -@end defun +@enumerate 0 +@item + seconds (0 - 61) +@item + minutes (0 - 59) +@item + hours since midnight (0 - 23) +@item + day of month (1 - 31) +@item + month (0 - 11). Note difference from @code{decode-universal-time}. +@item + the number of years since 1900. Note difference from +@code{decode-universal-time}. +@item + day of week (0 - 6) +@item + day of year (0 - 365) +@item + 1 for daylight savings, 0 for regular time +@end enumerate +@end deftp -@node R4RS Macros, Macro by Example, Defmacro, Macros -@section R4RS Macros +@defun gmtime caltime +Converts the calendar time @var{caltime} to UTC and returns it. -@code{(require 'macro)} is the appropriate call if you want R4RS -high-level macros but don't care about the low level implementation. If -an SLIB R4RS macro implementation is already loaded it will be used. -Otherwise, one of the R4RS macros implemetations is loaded. +@defunx localtime caltime tz +Returns @var{caltime} converted to UTC relative to timezone @var{tz}. -The SLIB R4RS macro implementations support the following uniform -interface: +@defunx localtime caltime +converts the calendar time @var{caltime} to a vector of integers +expressed relative to the user's time zone. @code{localtime} sets the +variable @var{*timezone*} with the difference between Coordinated +Universal Time (UTC) and local standard time in seconds +(@pxref{Time Zone,tzset}). -@defun macro:expand sexpression -Takes an R4RS expression, macro-expands it, and returns the result of -the macro expansion. @end defun -@defun macro:eval sexpression -Takes an R4RS expression, macro-expands it, evals the result of the -macro expansion, and returns the result of the evaluation. +@defun gmktime univtime +Converts a vector of integers in GMT Coordinated Universal Time (UTC) +format to a calendar time. + +@defunx mktime univtime +Converts a vector of integers in local Coordinated Universal Time (UTC) +format to a calendar time. + +@defunx mktime univtime tz +Converts a vector of integers in Coordinated Universal Time (UTC) format +(relative to time-zone @var{tz}) +to calendar time. @end defun -@deffn Procedure macro:load filename -@var{filename} should be a string. If filename names an existing file, -the @code{macro:load} procedure reads Scheme source code expressions and -definitions from the file and evaluates them sequentially. These source -code expressions and definitions may contain macro definitions. The -@code{macro:load} procedure does not affect the values returned by -@code{current-input-port} and @code{current-output-port}.@refill -@end deffn +@defun asctime univtime +Converts the vector of integers @var{caltime} in Coordinated +Universal Time (UTC) format into a string of the form +@code{"Wed Jun 30 21:49:08 1993"}. +@end defun -@node Macro by Example, Macros That Work, R4RS Macros, Macros -@section Macro by Example +@defun gtime caltime +@defunx ctime caltime +@defunx ctime caltime tz +Equivalent to @code{(asctime (gmtime @var{caltime}))}, +@code{(asctime (localtime @var{caltime}))}, and +@code{(asctime (localtime @var{caltime} @var{tz}))}, respectively. +@end defun -@code{(require 'macro-by-example)} -A vanilla implementation of @cite{Macro by Example} (Eugene Kohlbecker, -R4RS) by Dorai Sitaram, (dorai@@cs.rice.edu) using @code{defmacro}. +@node Common-Lisp Time, , Posix Time, Time and Date +@subsection Common-Lisp Time + +@defun get-decoded-time +Equivalent to @code{(decode-universal-time (get-universal-time))}. +@end defun -@itemize @bullet +@defun get-universal-time +Returns the current time as @dfn{Universal Time}, number of seconds +since 00:00:00 Jan 1, 1900 GMT. Note that the reference time is +different from @code{current-time}. +@end defun +@defun decode-universal-time univtime +Converts @var{univtime} to @dfn{Decoded Time} format. +Nine values are returned: +@enumerate 0 @item -generating hygienic global @code{define-syntax} Macro-by-Example macros -@strong{cheaply}. - + seconds (0 - 61) @item -can define macros which use @code{...}. - + minutes (0 - 59) @item -needn't worry about a lexical variable in a macro definition -clashing with a variable from the macro use context - + hours since midnight @item -don't suffer the overhead of redefining the repl if @code{defmacro} -natively supported (most implementations) + day of month +@item + month (1 - 12). Note difference from @code{gmtime} and @code{localtime}. +@item + year (A.D.). Note difference from @code{gmtime} and @code{localtime}. +@item + day of week (0 - 6) +@item + #t for daylight savings, #f otherwise +@item + hours west of GMT (-24 - +24) +@end enumerate -@end itemize -@subsection Caveat -These macros are not referentially transparent (@pxref{Macros, , ,r4rs, -Revised(4) Scheme}). Lexically scoped macros (i.e., @code{let-syntax} -and @code{letrec-syntax}) are not supported. In any case, the problem -of referential transparency gains poignancy only when @code{let-syntax} -and @code{letrec-syntax} are used. So you will not be courting -large-scale disaster unless you're using system-function names as local -variables with unintuitive bindings that the macro can't use. However, -if you must have the full @cite{r4rs} macro functionality, look to the -more featureful (but also more expensive) versions of syntax-rules -available in slib @ref{Macros That Work}, @ref{Syntactic Closures}, and -@ref{Syntax-Case Macros}. +Notice that the values returned by @code{decode-universal-time} do not +match the arguments to @code{encode-universal-time}. +@end defun -@defmac define-syntax keyword transformer-spec -The @var{keyword} is an identifier, and the @var{transformer-spec} -should be an instance of @code{syntax-rules}. +@defun encode-universal-time second minute hour date month year +@defunx encode-universal-time second minute hour date month year time-zone +Converts the arguments in Decoded Time format to Universal Time format. +If @var{time-zone} is not specified, the returned time is adjusted for +daylight saving time. Otherwise, no adjustment is performed. -The top-level syntactic environment is extended by binding the -@var{keyword} to the specified transformer. +Notice that the values returned by @code{decode-universal-time} do not +match the arguments to @code{encode-universal-time}. +@end defun -@example -(define-syntax let* - (syntax-rules () - ((let* () body1 body2 ...) - (let () body1 body2 ...)) - ((let* ((name1 val1) (name2 val2) ...) - body1 body2 ...) - (let ((name1 val1)) - (let* (( name2 val2) ...) - body1 body2 ...))))) -@end example -@end defmac -@defmac syntax-rules literals syntax-rule @dots{} -@var{literals} is a list of identifiers, and each @var{syntax-rule} -should be of the form +@node Vector Graphics, , Time and Date, Textual Conversion Packages +@section Vector Graphics -@code{(@var{pattern} @var{template})} +@menu +* Tektronix Graphics Support:: +@end menu -where the @var{pattern} and @var{template} are as in the grammar above. +@node Tektronix Graphics Support, , Vector Graphics, Vector Graphics +@subsection Tektronix Graphics Support -An instance of @code{syntax-rules} produces a new macro transformer by -specifying a sequence of hygienic rewrite rules. A use of a macro whose -keyword is associated with a transformer specified by -@code{syntax-rules} is matched against the patterns contained in the -@var{syntax-rule}s, beginning with the leftmost @var{syntax-rule}. -When a match is found, the macro use is trancribed hygienically -according to the template. +@emph{Note:} The Tektronix graphics support files need more work, and +are not complete. -Each pattern begins with the keyword for the macro. This keyword is not -involved in the matching and is not considered a pattern variable or -literal identifier. -@end defmac +@subsubsection Tektronix 4000 Series Graphics -@node Macros That Work, Syntactic Closures, Macro by Example, Macros -@section Macros That Work +The Tektronix 4000 series graphics protocol gives the user a 1024 by +1024 square drawing area. The origin is in the lower left corner of the +screen. Increasing y is up and increasing x is to the right. -@code{(require 'macros-that-work)} +The graphics control codes are sent over the current-output-port and can +be mixed with regular text and ANSI or other terminal control sequences. -@cite{Macros That Work} differs from the other R4RS macro -implementations in that it does not expand derived expression types to -primitive expression types. +@deffn Procedure tek40:init +@end deffn -@defun macro:expand expression -@defunx macwork:expand expression -Takes an R4RS expression, macro-expands it, and returns the result of -the macro expansion. -@end defun +@deffn Procedure tek40:graphics +@end deffn -@defun macro:eval expression -@defunx macwork:eval expression -@code{macro:eval} returns the value of @var{expression} in the current -top level environment. @var{expression} can contain macro definitions. -Side effects of @var{expression} will affect the top level -environment.@refill -@end defun +@deffn Procedure tek40:text +@end deffn -@deffn Procedure macro:load filename -@deffnx Procedure macwork:load filename -@var{filename} should be a string. If filename names an existing file, -the @code{macro:load} procedure reads Scheme source code expressions and -definitions from the file and evaluates them sequentially. These source -code expressions and definitions may contain macro definitions. The -@code{macro:load} procedure does not affect the values returned by -@code{current-input-port} and @code{current-output-port}.@refill +@deffn Procedure tek40:linetype linetype @end deffn -References: +@deffn Procedure tek40:move x y +@end deffn -The @cite{Revised^4 Report on the Algorithmic Language Scheme} Clinger -and Rees [editors]. To appear in LISP Pointers. Also available as a -technical report from the University of Oregon, MIT AI Lab, and -Cornell.@refill +@deffn Procedure tek40:draw x y +@end deffn -@center Macros That Work. Clinger and Rees. POPL '91. +@deffn Procedure tek40:put-text x y str +@end deffn -The supported syntax differs from the R4RS in that vectors are allowed -as patterns and as templates and are not allowed as pattern or template -data. +@deffn Procedure tek40:reset +@end deffn -@example -transformer spec @expansion{} (syntax-rules literals rules) -rules @expansion{} () - | (rule . rules) +@subsubsection Tektronix 4100 Series Graphics -rule @expansion{} (pattern template) +The graphics control codes are sent over the current-output-port and can +be mixed with regular text and ANSI or other terminal control sequences. -pattern @expansion{} pattern_var ; a symbol not in literals - | symbol ; a symbol in literals - | () - | (pattern . pattern) - | (ellipsis_pattern) - | #(pattern*) ; extends R4RS - | #(pattern* ellipsis_pattern) ; extends R4RS - | pattern_datum +@deffn Procedure tek41:init +@end deffn -template @expansion{} pattern_var - | symbol - | () - | (template2 . template2) - | #(template*) ; extends R4RS - | pattern_datum +@deffn Procedure tek41:reset +@end deffn -template2 @expansion{} template - | ellipsis_template +@deffn Procedure tek41:graphics +@end deffn -pattern_datum @expansion{} string ; no vector - | character - | boolean - | number +@deffn Procedure tek41:move x y +@end deffn -ellipsis_pattern @expansion{} pattern ... +@deffn Procedure tek41:draw x y +@end deffn -ellipsis_template @expansion{} template ... +@deffn Procedure tek41:point x y number +@end deffn -pattern_var @expansion{} symbol ; not in literals +@deffn Procedure tek41:encode-x-y x y +@end deffn -literals @expansion{} () - | (symbol . literals) -@end example +@deffn Procedure tek41:encode-int number +@end deffn -@subsection Definitions -@table @asis +@node Mathematical Packages, Database Packages, Textual Conversion Packages, Top +@chapter Mathematical Packages -@item Scope of an ellipsis -Within a pattern or template, the scope of an ellipsis (@code{...}) is -the pattern or template that appears to its left. +@menu +* Bit-Twiddling:: 'logical +* Modular Arithmetic:: 'modular +* Prime Testing and Generation:: 'primes +* Prime Factorization:: 'factor +* Random Numbers:: 'random +* Cyclic Checksum:: 'make-crc +* Plotting:: 'charplot +* Root Finding:: 'root +* Commutative Rings:: 'commutative-ring +* Determinant:: +@end menu -@item Rank of a pattern variable -The rank of a pattern variable is the number of ellipses within whose -scope it appears in the pattern. -@item Rank of a subtemplate -The rank of a subtemplate is the number of ellipses within whose scope -it appears in the template. +@node Bit-Twiddling, Modular Arithmetic, Mathematical Packages, Mathematical Packages +@section Bit-Twiddling -@item Template rank of an occurrence of a pattern variable -The template rank of an occurrence of a pattern variable within a -template is the rank of that occurrence, viewed as a subtemplate. +@code{(require 'logical)} +@ftindex logical -@item Variables bound by a pattern -The variables bound by a pattern are the pattern variables that appear -within it. +The bit-twiddling functions are made available through the use of the +@code{logical} package. @code{logical} is loaded by inserting +@code{(require 'logical)} before the code that uses these +@ftindex logical +functions.@refill + +@defun logand n1 n1 +Returns the integer which is the bit-wise AND of the two integer +arguments. + +Example: +@lisp +(number->string (logand #b1100 #b1010) 2) + @result{} "1000" +@end lisp +@end defun + +@defun logior n1 n2 +Returns the integer which is the bit-wise OR of the two integer +arguments. + +Example: +@lisp +(number->string (logior #b1100 #b1010) 2) + @result{} "1110" +@end lisp +@end defun -@item Referenced variables of a subtemplate -The referenced variables of a subtemplate are the pattern variables that -appear within it. +@defun logxor n1 n2 +Returns the integer which is the bit-wise XOR of the two integer +arguments. -@item Variables opened by an ellipsis template -The variables opened by an ellipsis template are the referenced pattern -variables whose rank is greater than the rank of the ellipsis template. +Example: +@lisp +(number->string (logxor #b1100 #b1010) 2) + @result{} "110" +@end lisp +@end defun -@end table +@defun lognot n +Returns the integer which is the 2s-complement of the integer argument. -@subsection Restrictions +Example: +@lisp +(number->string (lognot #b10000000) 2) + @result{} "-10000001" +(number->string (lognot #b0) 2) + @result{} "-1" +@end lisp +@end defun -No pattern variable appears more than once within a pattern. +@defun logtest j k +@example +(logtest j k) @equiv{} (not (zero? (logand j k))) -For every occurrence of a pattern variable within a template, the -template rank of the occurrence must be greater than or equal to the -pattern variable's rank. +(logtest #b0100 #b1011) @result{} #f +(logtest #b0100 #b0111) @result{} #t +@end example +@end defun -Every ellipsis template must open at least one variable. +@defun logbit? index j +@example +(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j) -For every ellipsis template, the variables opened by an ellipsis -template must all be bound to sequences of the same length. +(logbit? 0 #b1101) @result{} #t +(logbit? 1 #b1101) @result{} #f +(logbit? 2 #b1101) @result{} #t +(logbit? 3 #b1101) @result{} #t +(logbit? 4 #b1101) @result{} #f +@end example +@end defun -The compiled form of a @var{rule} is +@defun ash int count +Returns an integer equivalent to +@code{(inexact->exact (floor (* @var{int} (expt 2 @var{count}))))}.@refill -@example -rule @expansion{} (pattern template inserted) +Example: +@lisp +(number->string (ash #b1 3) 2) + @result{} "1000" +(number->string (ash #b1010 -1) 2) + @result{} "101" +@end lisp +@end defun -pattern @expansion{} pattern_var - | symbol - | () - | (pattern . pattern) - | ellipsis_pattern - | #(pattern) - | pattern_datum +@defun logcount n +Returns the number of bits in integer @var{n}. If integer is positive, +the 1-bits in its binary representation are counted. If negative, the +0-bits in its two's-complement binary representation are counted. If 0, +0 is returned. -template @expansion{} pattern_var - | symbol - | () - | (template2 . template2) - | #(pattern) - | pattern_datum +Example: +@lisp +(logcount #b10101010) + @result{} 4 +(logcount 0) + @result{} 0 +(logcount -2) + @result{} 1 +@end lisp +@end defun -template2 @expansion{} template - | ellipsis_template +@defun integer-length n +Returns the number of bits neccessary to represent @var{n}. -pattern_datum @expansion{} string - | character - | boolean - | number +Example: +@lisp +(integer-length #b10101010) + @result{} 8 +(integer-length 0) + @result{} 0 +(integer-length #b1111) + @result{} 4 +@end lisp +@end defun -pattern_var @expansion{} #(V symbol rank) +@defun integer-expt n k +Returns @var{n} raised to the non-negative integer exponent @var{k}. -ellipsis_pattern @expansion{} #(E pattern pattern_vars) +Example: +@lisp +(integer-expt 2 5) + @result{} 32 +(integer-expt -3 3) + @result{} -27 +@end lisp +@end defun -ellipsis_template @expansion{} #(E template pattern_vars) +@defun bit-extract n start end +Returns the integer composed of the @var{start} (inclusive) through +@var{end} (exclusive) bits of @var{n}. The @var{start}th bit becomes +the 0-th bit in the result.@refill -inserted @expansion{} () - | (symbol . inserted) +Example: +@lisp +(number->string (bit-extract #b1101101010 0 4) 2) + @result{} "1010" +(number->string (bit-extract #b1101101010 4 9) 2) + @result{} "10110" +@end lisp +@end defun -pattern_vars @expansion{} () - | (pattern_var . pattern_vars) -rank @expansion{} exact non-negative integer -@end example +@node Modular Arithmetic, Prime Testing and Generation, Bit-Twiddling, Mathematical Packages +@section Modular Arithmetic -where V and E are unforgeable values. +@code{(require 'modular)} +@ftindex modular -The pattern variables associated with an ellipsis pattern are the -variables bound by the pattern, and the pattern variables associated -with an ellipsis template are the variables opened by the ellipsis -template. +@defun extended-euclid n1 n2 +Returns a list of 3 integers @code{(d x y)} such that d = gcd(@var{n1}, +@var{n2}) = @var{n1} * x + @var{n2} * y.@refill +@end defun -If the template contains a big chunk that contains no pattern variables -or inserted identifiers, then the big chunk will be copied -unnecessarily. That shouldn't matter very often. +@defun symmetric:modulus n +Returns @code{(quotient (+ -1 n) -2)} for positive odd integer @var{n}. +@end defun +@defun modulus->integer modulus +Returns the non-negative integer characteristic of the ring formed when +@var{modulus} is used with @code{modular:} procedures. +@end defun +@defun modular:normalize modulus n +Returns the integer @code{(modulo @var{n} (modulus->integer +@var{modulus}))} in the representation specified by @var{modulus}. +@end defun +@noindent +The rest of these functions assume normalized arguments; That is, the +arguments are constrained by the following table: +@noindent +For all of these functions, if the first argument (@var{modulus}) is: +@table @code +@item positive? +Work as before. The result is between 0 and @var{modulus}. -@node Syntactic Closures, Syntax-Case Macros, Macros That Work, Macros -@section Syntactic Closures +@item zero? +The arguments are treated as integers. An integer is returned. -@code{(require 'syntactic-closures)} +@item negative? +The arguments and result are treated as members of the integers modulo +@code{(+ 1 (* -2 @var{modulus}))}, but with @dfn{symmetric} +representation; i.e. @code{(<= (- @var{modulus}) @var{n} +@var{modulus})}. +@end table -@defun macro:expand expression -@defunx synclo:expand expression -Returns scheme code with the macros and derived expression types of -@var{expression} expanded to primitive expression types.@refill -@end defun +@noindent +If all the arguments are fixnums the computation will use only fixnums. -@defun macro:eval expression -@defunx synclo:eval expression -@code{macro:eval} returns the value of @var{expression} in the current -top level environment. @var{expression} can contain macro definitions. -Side effects of @var{expression} will affect the top level -environment.@refill +@defun modular:invertable? modulus k +Returns @code{#t} if there exists an integer n such that @var{k} * n +@equiv{} 1 mod @var{modulus}, and @code{#f} otherwise. @end defun -@deffn Procedure macro:load filename -@deffnx Procedure synclo:load filename -@var{filename} should be a string. If filename names an existing file, -the @code{macro:load} procedure reads Scheme source code expressions and -definitions from the file and evaluates them sequentially. These -source code expressions and definitions may contain macro definitions. -The @code{macro:load} procedure does not affect the values returned by -@code{current-input-port} and @code{current-output-port}.@refill -@end deffn - -@subsection Syntactic Closure Macro Facility +@defun modular:invert modulus k2 +Returns an integer n such that 1 = (n * @var{k2}) mod @var{modulus}. If +@var{k2} has no inverse mod @var{modulus} an error is signaled. +@end defun -@center A Syntactic Closures Macro Facility -@center by Chris Hanson -@center 9 November 1991 +@defun modular:negate modulus k2 +Returns (@minus{}@var{k2}) mod @var{modulus}. +@end defun -This document describes @dfn{syntactic closures}, a low-level macro -facility for the Scheme programming language. The facility is an -alternative to the low-level macro facility described in the -@cite{Revised^4 Report on Scheme.} This document is an addendum to that -report. +@defun modular:+ modulus k2 k3 +Returns (@var{k2} + @var{k3}) mod @var{modulus}. +@end defun -The syntactic closures facility extends the BNF rule for -@var{transformer spec} to allow a new keyword that introduces a -low-level macro transformer:@refill -@example -@var{transformer spec} := (transformer @var{expression}) -@end example +@defun modular:@minus{} modulus k2 k3 +Returns (@var{k2} @minus{} @var{k3}) mod @var{modulus}. +@end defun -Additionally, the following procedures are added: -@lisp -make-syntactic-closure -capture-syntactic-environment -identifier? -identifier=? -@end lisp +@defun modular:* modulus k2 k3 +Returns (@var{k2} * @var{k3}) mod @var{modulus}. -The description of the facility is divided into three parts. The first -part defines basic terminology. The second part describes how macro -transformers are defined. The third part describes the use of -@dfn{identifiers}, which extend the syntactic closure mechanism to be -compatible with @code{syntax-rules}.@refill +The Scheme code for @code{modular:*} with negative @var{modulus} is not +completed for fixnum-only implementations. +@end defun -@subsubsection Terminology +@defun modular:expt modulus k2 k3 +Returns (@var{k2} ^ @var{k3}) mod @var{modulus}. +@end defun -This section defines the concepts and data types used by the syntactic -closures facility. -@itemize +@node Prime Testing and Generation, Prime Factorization, Modular Arithmetic, Mathematical Packages +@section Prime Testing and Generation -@item @dfn{Forms} are the syntactic entities out of which programs are -recursively constructed. A form is any expression, any definition, any -syntactic keyword, or any syntactic closure. The variable name that -appears in a @code{set!} special form is also a form. Examples of -forms:@refill -@lisp -17 -#t -car -(+ x 4) -(lambda (x) x) -(define pi 3.14159) -if -define -@end lisp +@code{(require 'primes)} +@ftindex primes -@item An @dfn{alias} is an alternate name for a given symbol. It can -appear anywhere in a form that the symbol could be used, and when quoted -it is replaced by the symbol; however, it does not satisfy the predicate -@code{symbol?}. Macro transformers rarely distinguish symbols from -aliases, referring to both as identifiers.@refill +This package tests and generates prime numbers. The strategy used is +as follows: -@item A @dfn{syntactic} environment maps identifiers to their -meanings. More precisely, it determines whether an identifier is a -syntactic keyword or a variable. If it is a keyword, the meaning is an -interpretation for the form in which that keyword appears. If it is a -variable, the meaning identifies which binding of that variable is -referenced. In short, syntactic environments contain all of the -contextual information necessary for interpreting the meaning of a -particular form.@refill +@itemize @bullet +@item +First, use trial division by small primes (primes less than 1000) to +quickly weed out composites with small factors. As a side benefit, this +makes the test precise for numbers up to one million. +@item +Second, apply the Miller-Rabin primality test to detect (with high +probability) any remaining composites. +@end itemize -@item A @dfn{syntactic closure} consists of a form, a syntactic -environment, and a list of identifiers. All identifiers in the form -take their meaning from the syntactic environment, except those in the -given list. The identifiers in the list are to have their meanings -determined later. A syntactic closure may be used in any context in -which its form could have been used. Since a syntactic closure is also -a form, it may not be used in contexts where a form would be illegal. -For example, a form may not appear as a clause in the cond special form. -A syntactic closure appearing in a quoted structure is replaced by its -form.@refill +The Miller-Rabin test is a Monte-Carlo test---in other words, it's fast +and it gets the right answer with high probability. For a candidate +that @emph{is} prime, the Miller-Rabin test is certain to report +"prime"; it will never report "composite". However, for a candidate +that is composite, there is a (small) probability that the Miller-Rabin +test will erroneously report "prime". This probability can be made +arbitarily small by adjusting the number of iterations of the +Miller-Rabin test. -@end itemize +@defun probably-prime? candidate +@defunx probably-prime? candidate iter +Returns @code{#t} if @code{candidate} is probably prime. The optional +parameter @code{iter} controls the number of iterations of the +Miller-Rabin test. The probability of a composite candidate being +mistaken for a prime is at most @code{(1/4)^iter}. The default value of +@code{iter} is 15, which makes the probability less than 1 in 10^9. -@subsubsection Transformer Definition +@end defun -This section describes the @code{transformer} special form and the -procedures @code{make-syntactic-closure} and -@code{capture-syntactic-environment}.@refill +@defun primes< start count +@defunx primes< start count iter +@defunx primes> start count +@defunx primes> start count iter +Returns a list of the first @code{count} odd probable primes less (more) +than or equal to @code{start}. The optional parameter @code{iter} +controls the number of iterations of the Miller-Rabin test for each +candidate. The probability of a composite candidate being mistaken for +a prime is at most @code{(1/4)^iter}. The default value of @code{iter} +is 15, which makes the probability less than 1 in 10^9. -@deffn Syntax transformer expression +@end defun -Syntax: It is an error if this syntax occurs except as a -@var{transformer spec}.@refill +@menu +* The Miller-Rabin Test:: How the Miller-Rabin test works +@end menu -Semantics: The @var{expression} is evaluated in the standard transformer -environment to yield a macro transformer as described below. This macro -transformer is bound to a macro keyword by the special form in which the -@code{transformer} expression appears (for example, -@code{let-syntax}).@refill +@node The Miller-Rabin Test, , Prime Testing and Generation, Prime Testing and Generation +@subsection Theory -A @dfn{macro transformer} is a procedure that takes two arguments, a -form and a syntactic environment, and returns a new form. The first -argument, the @dfn{input form}, is the form in which the macro keyword -occurred. The second argument, the @dfn{usage environment}, is the -syntactic environment in which the input form occurred. The result of -the transformer, the @dfn{output form}, is automatically closed in the -@dfn{transformer environment}, which is the syntactic environment in -which the @code{transformer} expression occurred.@refill +Rabin and Miller's result can be summarized as follows. Let @code{p} +(the candidate prime) be any odd integer greater than 2. Let @code{b} +(the "base") be an integer in the range @code{2 ... p-1}. There is a +fairly simple Boolean function---call it @code{C}, for +"Composite"---with the following properties: +@itemize @bullet -For example, here is a definition of a push macro using -@code{syntax-rules}:@refill -@lisp -(define-syntax push - (syntax-rules () - ((push item list) - (set! list (cons item list))))) -@end lisp +@item +If @code{p} is prime, @code{C(p, b)} is false for all @code{b} in the range +@code{2 ... p-1}. -Here is an equivalent definition using @code{transformer}: -@lisp -(define-syntax push - (transformer - (lambda (exp env) - (let ((item - (make-syntactic-closure env '() (cadr exp))) - (list - (make-syntactic-closure env '() (caddr exp)))) - `(set! ,list (cons ,item ,list)))))) -@end lisp +@item +If @code{p} is composite, @code{C(p, b)} is false for at most 1/4 of all +@code{b} in the range @code{ 2 ... p-1}. (If the test fails for base +@code{b}, @code{p} is called a @emph{strong pseudo-prime to base +@code{b}}.) -In this example, the identifiers @code{set!} and @code{cons} are closed -in the transformer environment, and thus will not be affected by the -meanings of those identifiers in the usage environment -@code{env}.@refill +@end itemize +For details of @code{C}, and why it fails for at most 1/4 of the +potential bases, please consult a book on number theory or cryptography +such as "A Course in Number Theory and Cryptography" by Neal Koblitz, +published by Springer-Verlag 1994. -Some macros may be non-hygienic by design. For example, the following -defines a loop macro that implicitly binds @code{exit} to an escape -procedure. The binding of @code{exit} is intended to capture free -references to @code{exit} in the body of the loop, so @code{exit} must -be left free when the body is closed:@refill -@lisp -(define-syntax loop - (transformer - (lambda (exp env) - (let ((body (cdr exp))) - `(call-with-current-continuation - (lambda (exit) - (let f () - ,@@(map (lambda (exp) - (make-syntactic-closure env '(exit) - exp)) - body) - (f)))))))) -@end lisp +There is nothing probablistic about this result. It's true for all +@code{p}. If we had time to test @code{(1/4)p + 1} different bases, we +could definitively determine the primality of @code{p}. For large +candidates, that would take much too long---much longer than the simple +approach of dividing by all numbers up to @code{sqrt(p)}. This is +where probability enters the picture. -To assign meanings to the identifiers in a form, use -@code{make-syntactic-closure} to close the form in a syntactic -environment.@refill -@end deffn +Suppose we have some candidate prime @code{p}. Pick a random integer +@code{b} in the range @code{2 ... p-1}. Compute @code{C(p,b)}. If +@code{p} is prime, the result will certainly be false. If @code{p} is +composite, the probability is at most 1/4 that the result will be false +(demonstrating that @code{p} is a strong pseudoprime to base @code{b}). +The test can be repeated with other random bases. If @code{p} is prime, +each test is certain to return false. If @code{p} is composite, the +probability of @code{C(p,b)} returning false is at most 1/4 for each +test. Since the @code{b} are chosen at random, the tests outcomes are +independent. So if @code{p} is composite and the test is repeated, say, +15 times, the probability of it returning false all fifteen times is at +most (1/4)^15, or about 10^-9. If the test is repeated 30 times, the +probability of failure drops to at most 8.3e-25. -@defun make-syntactic-closure environment free-names form +Rabin and Miller's result holds for @emph{all} candidates @code{p}. +However, if the candidate @code{p} is picked at random, the probability +of the Miller-Rabin test failing is much less than the computed bound. +This is because, for @emph{most} composite numbers, the fraction of +bases that cause the test to fail is much less than 1/4. For example, +if you pick a random odd number less than 1000 and apply the +Miller-Rabin test with only 3 random bases, the computed failure bound +is (1/4)^3, or about 1.6e-2. However, the actual probability of failure +is much less---about 7.2e-5. If you accidentally pick 703 to test for +primality, the probability of failure is (161/703)^3, or about 1.2e-2, +which is almost as high as the computed bound. This is because 703 is a +strong pseudoprime to 161 bases. But if you pick at random there is +only a small chance of picking 703, and no other number less than 1000 +has that high a percentage of pseudoprime bases. -@var{environment} must be a syntactic environment, @var{free-names} must -be a list of identifiers, and @var{form} must be a form. -@code{make-syntactic-closure} constructs and returns a syntactic closure -of @var{form} in @var{environment}, which can be used anywhere that -@var{form} could have been used. All the identifiers used in -@var{form}, except those explicitly excepted by @var{free-names}, obtain -their meanings from @var{environment}.@refill +The Miller-Rabin test is sometimes used in a slightly different fashion, +where it can, at least in principle, cause problems. The weaker version +uses small prime bases instead of random bases. If you are picking +candidates at random and testing for primality, this works well since +very few composites are strong pseudo-primes to small prime bases. (For +example, there is only one composite less than 2.5e10 that is a strong +pseudo-prime to the bases 2, 3, 5, and 7.) The problem with this +approach is that once a candidate has been picked, the test is +deterministic. This distinction is subtle, but real. With the +randomized test, for @emph{any} candidate you pick---even if your +candidate-picking procedure is strongly biased towards troublesome +numbers, the test will work with high probability. With the +deterministic version, for any particular candidate, the test will +either work (with probability 1), or fail (with probability 1). It +won't fail for very many candidates, but that won't be much consolation +if your candidate-picking procedure is somehow biased toward troublesome +numbers. -Here is an example where @var{free-names} is something other than the -empty list. It is instructive to compare the use of @var{free-names} in -this example with its use in the @code{loop} example above: the examples -are similar except for the source of the identifier being left -free.@refill -@lisp -(define-syntax let1 - (transformer - (lambda (exp env) - (let ((id (cadr exp)) - (init (caddr exp)) - (exp (cadddr exp))) - `((lambda (,id) - ,(make-syntactic-closure env (list id) exp)) - ,(make-syntactic-closure env '() init)))))) -@end lisp -@code{let1} is a simplified version of @code{let} that only binds a -single identifier, and whose body consists of a single expression. When -the body expression is syntactically closed in its original syntactic -environment, the identifier that is to be bound by @code{let1} must be -left free, so that it can be properly captured by the @code{lambda} in -the output form.@refill +@node Prime Factorization, Random Numbers, Prime Testing and Generation, Mathematical Packages +@section Prime Factorization -To obtain a syntactic environment other than the usage environment, use -@code{capture-syntactic-environment}.@refill +@code{(require 'factor)} +@ftindex factor + + +@defun factor k +Returns a list of the prime factors of @var{k}. The order of the +factors is unspecified. In order to obtain a sorted list do +@code{(sort! (factor k) <)}.@refill @end defun -@defun capture-syntactic-environment procedure +@emph{Note:} The rest of these procedures implement the Solovay-Strassen +primality test. This test has been superseeded by the faster +@xref{Prime Testing and Generation, probably-prime?}. However these are +left here as they take up little space and may be of use to an +implementation without bignums. -@code{capture-syntactic-environment} returns a form that will, when -transformed, call @var{procedure} on the current syntactic environment. -@var{procedure} should compute and return a new form to be transformed, -in that same syntactic environment, in place of the form.@refill +See Robert Solovay and Volker Strassen, @cite{A Fast Monte-Carlo Test +for Primality}, SIAM Journal on Computing, 1977, pp 84-85. -An example will make this clear. Suppose we wanted to define a simple -@code{loop-until} keyword equivalent to@refill -@lisp -(define-syntax loop-until - (syntax-rules () - ((loop-until id init test return step) - (letrec ((loop - (lambda (id) - (if test return (loop step))))) - (loop init))))) -@end lisp +@defun jacobi-symbol p q +Returns the value (+1, @minus{}1, or 0) of the Jacobi-Symbol of exact +non-negative integer @var{p} and exact positive odd integer +@var{q}.@refill +@end defun -The following attempt at defining @code{loop-until} has a subtle bug: -@lisp -(define-syntax loop-until - (transformer - (lambda (exp env) - (let ((id (cadr exp)) - (init (caddr exp)) - (test (cadddr exp)) - (return (cadddr (cdr exp))) - (step (cadddr (cddr exp))) - (close - (lambda (exp free) - (make-syntactic-closure env free exp)))) - `(letrec ((loop - (lambda (,id) - (if ,(close test (list id)) - ,(close return (list id)) - (loop ,(close step (list id))))))) - (loop ,(close init '()))))))) -@end lisp +@defun prime? p +Returns @code{#f} if @var{p} is composite; @code{#t} if @var{p} is +prime. There is a slight chance @code{(expt 2 (- prime:trials))} that a +composite will return @code{#t}.@refill +@end defun -This definition appears to take all of the proper precautions to prevent -unintended captures. It carefully closes the subexpressions in their -original syntactic environment and it leaves the @code{id} identifier -free in the @code{test}, @code{return}, and @code{step} expressions, so -that it will be captured by the binding introduced by the @code{lambda} -expression. Unfortunately it uses the identifiers @code{if} and -@code{loop} within that @code{lambda} expression, so if the user of -@code{loop-until} just happens to use, say, @code{if} for the -identifier, it will be inadvertently captured.@refill +@defun prime:trials +Is the maxinum number of iterations of Solovay-Strassen that will be +done to test a number for primality. +@end defun -The syntactic environment that @code{if} and @code{loop} want to be -exposed to is the one just outside the @code{lambda} expression: before -the user's identifier is added to the syntactic environment, but after -the identifier loop has been added. -@code{capture-syntactic-environment} captures exactly that environment -as follows:@refill -@lisp -(define-syntax loop-until - (transformer - (lambda (exp env) - (let ((id (cadr exp)) - (init (caddr exp)) - (test (cadddr exp)) - (return (cadddr (cdr exp))) - (step (cadddr (cddr exp))) - (close - (lambda (exp free) - (make-syntactic-closure env free exp)))) - `(letrec ((loop - ,(capture-syntactic-environment - (lambda (env) - `(lambda (,id) - (,(make-syntactic-closure env '() `if) - ,(close test (list id)) - ,(close return (list id)) - (,(make-syntactic-closure env '() - `loop) - ,(close step (list id))))))))) - (loop ,(close init '()))))))) -@end lisp -In this case, having captured the desired syntactic environment, it is -convenient to construct syntactic closures of the identifiers @code{if} -and the @code{loop} and use them in the body of the -@code{lambda}.@refill -A common use of @code{capture-syntactic-environment} is to get the -transformer environment of a macro transformer:@refill -@lisp -(transformer - (lambda (exp env) - (capture-syntactic-environment - (lambda (transformer-env) - ...)))) -@end lisp -@end defun +@node Random Numbers, Cyclic Checksum, Prime Factorization, Mathematical Packages +@section Random Numbers -@subsubsection Identifiers +@code{(require 'random)} +@ftindex random -This section describes the procedures that create and manipulate -identifiers. Previous syntactic closure proposals did not have an -identifier data type -- they just used symbols. The identifier data -type extends the syntactic closures facility to be compatible with the -high-level @code{syntax-rules} facility.@refill -As discussed earlier, an identifier is either a symbol or an -@dfn{alias}. An alias is implemented as a syntactic closure whose -@dfn{form} is an identifier:@refill -@lisp -(make-syntactic-closure env '() 'a) - @result{} an @dfn{alias} -@end lisp +@deffn Procedure random n +@deffnx Procedure random n state +Accepts a positive integer or real @var{n} and returns a number of the +same type between zero (inclusive) and @var{n} (exclusive). The values +returned have a uniform distribution.@refill -Aliases are implemented as syntactic closures because they behave just -like syntactic closures most of the time. The difference is that an -alias may be bound to a new value (for example by @code{lambda} or -@code{let-syntax}); other syntactic closures may not be used this way. -If an alias is bound, then within the scope of that binding it is looked -up in the syntactic environment just like any other identifier.@refill +The optional argument @var{state} must be of the type produced by +@code{(make-random-state)}. It defaults to the value of the variable +@code{*random-state*}. This object is used to maintain the state of the +pseudo-random-number generator and is altered as a side effect of the +@code{random} operation.@refill +@end deffn -Aliases are used in the implementation of the high-level facility -@code{syntax-rules}. A macro transformer created by @code{syntax-rules} -uses a template to generate its output form, substituting subforms of -the input form into the template. In a syntactic closures -implementation, all of the symbols in the template are replaced by -aliases closed in the transformer environment, while the output form -itself is closed in the usage environment. This guarantees that the -macro transformation is hygienic, without requiring the transformer to -know the syntactic roles of the substituted input subforms. +@defvar *random-state* +Holds a data structure that encodes the internal state of the +random-number generator that @code{random} uses by default. The nature +of this data structure is implementation-dependent. It may be printed +out and successfully read back in, but may or may not function correctly +as a random-number state object in another implementation.@refill +@end defvar -@defun identifier? object -Returns @code{#t} if @var{object} is an identifier, otherwise returns -@code{#f}. Examples:@refill -@lisp -(identifier? 'a) - @result{} #t -(identifier? (make-syntactic-closure env '() 'a)) - @result{} #t -(identifier? "a") - @result{} #f -(identifier? #\a) - @result{} #f -(identifier? 97) - @result{} #f -(identifier? #f) - @result{} #f -(identifier? '(a)) - @result{} #f -(identifier? '#(a)) - @result{} #f -@end lisp +@deffn Procedure make-random-state +@deffnx Procedure make-random-state state +Returns a new object of type suitable for use as the value of the +variable @code{*random-state*} and as a second argument to +@code{random}. If argument @var{state} is given, a copy of it is +returned. Otherwise a copy of @code{*random-state*} is returned.@refill +@end deffn -The predicate @code{eq?} is used to determine if two identifers are -``the same''. Thus @code{eq?} can be used to compare identifiers -exactly as it would be used to compare symbols. Often, though, it is -useful to know whether two identifiers ``mean the same thing''. For -example, the @code{cond} macro uses the symbol @code{else} to identify -the final clause in the conditional. A macro transformer for -@code{cond} cannot just look for the symbol @code{else}, because the -@code{cond} form might be the output of another macro transformer that -replaced the symbol @code{else} with an alias. Instead the transformer -must look for an identifier that ``means the same thing'' in the usage -environment as the symbol @code{else} means in the transformer -environment.@refill -@end defun +If inexact numbers are support by the Scheme implementation, +@file{randinex.scm} will be loaded as well. @file{randinex.scm} +contains procedures for generating inexact distributions.@refill -@defun identifier=? environment1 identifier1 environment2 identifier2 -@var{environment1} and @var{environment2} must be syntactic -environments, and @var{identifier1} and @var{identifier2} must be -identifiers. @code{identifier=?} returns @code{#t} if the meaning of -@var{identifier1} in @var{environment1} is the same as that of -@var{identifier2} in @var{environment2}, otherwise it returns @code{#f}. -Examples:@refill +@deffn Procedure random:uniform state +Returns an uniformly distributed inexact real random number in the +range between 0 and 1. +@end deffn -@lisp -(let-syntax - ((foo - (transformer - (lambda (form env) - (capture-syntactic-environment - (lambda (transformer-env) - (identifier=? transformer-env 'x env 'x))))))) - (list (foo) - (let ((x 3)) - (foo)))) - @result{} (#t #f) -@end lisp +@deffn Procedure random:solid-sphere! vect +@deffnx Procedure random:solid-sphere! vect state +Fills @var{vect} with inexact real random numbers the sum of whose +squares is less than 1.0. Thinking of @var{vect} as coordinates in +space of dimension @var{n} = @code{(vector-length @var{vect})}, the +coordinates are uniformly distributed within the unit @var{n}-shere. +The sum of the squares of the numbers is returned.@refill +@end deffn + +@deffn Procedure random:hollow-sphere! vect +@deffnx Procedure random:hollow-sphere! vect state +Fills @var{vect} with inexact real random numbers the sum of whose +squares is equal to 1.0. Thinking of @var{vect} as coordinates in space +of dimension n = @code{(vector-length @var{vect})}, the coordinates are +uniformly distributed over the surface of the unit n-shere.@refill +@end deffn + +@deffn Procedure random:normal +@deffnx Procedure random:normal state +Returns an inexact real in a normal distribution with mean 0 and +standard deviation 1. For a normal distribution with mean @var{m} and +standard deviation @var{d} use @code{(+ @var{m} (* @var{d} +(random:normal)))}.@refill +@end deffn -@lisp -(let-syntax ((bar foo)) - (let-syntax - ((foo - (transformer - (lambda (form env) - (capture-syntactic-environment - (lambda (transformer-env) - (identifier=? transformer-env 'foo - env (cadr form)))))))) - (list (foo foo) - (foobar)))) - @result{} (#f #t) -@end lisp -@end defun +@deffn Procedure random:normal-vector! vect +@deffnx Procedure random:normal-vector! vect state +Fills @var{vect} with inexact real random numbers which are independent +and standard normally distributed (i.e., with mean 0 and variance 1). +@end deffn -@subsubsection Acknowledgements +@deffn Procedure random:exp +@deffnx Procedure random:exp state +Returns an inexact real in an exponential distribution with mean 1. For +an exponential distribution with mean @var{u} use (* @var{u} +(random:exp)).@refill +@end deffn -The syntactic closures facility was invented by Alan Bawden and Jonathan -Rees. The use of aliases to implement @code{syntax-rules} was invented -by Alan Bawden (who prefers to call them @dfn{synthetic names}). Much -of this proposal is derived from an earlier proposal by Alan -Bawden.@refill +@node Cyclic Checksum, Plotting, Random Numbers, Mathematical Packages +@section Cyclic Checksum +@code{(require 'make-crc)} +@ftindex make-crc +@defun make-port-crc +@defunx make-port-crc degree +@defunx make-port-crc degree generator +Returns an expression for a procedure of one argument, a port. This +procedure reads characters from the port until the end of file and +returns the integer checksum of the bytes read. +The integer @var{degree}, if given, specifies the degree of the +polynomial being computed -- which is also the number of bits computed +in the checksums. The default value is 32. -@node Syntax-Case Macros, Fluid-Let, Syntactic Closures, Macros -@section Syntax-Case Macros +The integer @var{generator} specifies the polynomial being computed. +The power of 2 generating each 1 bit is the exponent of a term of the +polynomial. The bit at position @var{degree} is implicit and should not +be part of @var{generator}. This allows systems with numbers limited to +32 bits to calculate 32 bit checksums. The default value of +@var{generator} when @var{degree} is 32 (its default) is: -@code{(require 'syntax-case)} +@example +(make-port-crc 32 #b00000100110000010001110110110111) +@end example -@defun macro:expand expression -@defunx syncase:expand expression -Returns scheme code with the macros and derived expression types of -@var{expression} expanded to primitive expression types.@refill -@end defun +Creates a procedure to calculate the P1003.2/D11.2 (POSIX.2) 32-bit +checksum from the polynomial: -@defun macro:eval expression -@defunx syncase:eval expression -@code{macro:eval} returns the value of @var{expression} in the current -top level environment. @var{expression} can contain macro definitions. -Side effects of @var{expression} will affect the top level -environment.@refill +@example + 32 26 23 22 16 12 11 + ( x + x + x + x + x + x + x + + + 10 8 7 5 4 2 1 + x + x + x + x + x + x + x + 1 ) mod 2 +@end example @end defun -@deffn Procedure macro:load filename -@deffnx Procedure syncase:load filename -@var{filename} should be a string. If filename names an existing file, -the @code{macro:load} procedure reads Scheme source code expressions and -definitions from the file and evaluates them sequentially. These -source code expressions and definitions may contain macro definitions. -The @code{macro:load} procedure does not affect the values returned by -@code{current-input-port} and @code{current-output-port}.@refill -@end deffn +@example +(require 'make-crc) +@ftindex make-crc +(define crc32 (slib:eval (make-port-crc))) +(define (file-check-sum file) (call-with-input-file file crc32)) +(file-check-sum (in-vicinity (library-vicinity) "ratize.scm")) -This is version 2.1 of @code{syntax-case}, the low-level macro facility -proposed and implemented by Robert Hieb and R. Kent Dybvig. +@result{} 3553047446 +@end example -This version is further adapted by Harald Hanche-Olsen - to make it compatible with, and easily usable -with, SLIB. Mainly, these adaptations consisted of: +@node Plotting, Root Finding, Cyclic Checksum, Mathematical Packages +@section Plotting on Character Devices -@itemize @bullet -@item -Removing white space from @file{expand.pp} to save space in the -distribution. This file is not meant for human readers anyway@dots{} +@code{(require 'charplot)} +@ftindex charplot -@item -Removed a couple of Chez scheme dependencies. +The plotting procedure is made available through the use of the +@code{charplot} package. @code{charplot} is loaded by inserting +@code{(require 'charplot)} before the code that uses this +@ftindex charplot +procedure.@refill -@item -Renamed global variables used to minimize the possibility of name -conflicts. +@defvar charplot:height +The number of rows to make the plot vertically. +@end defvar -@item -Adding an SLIB-specific initialization file. +@defvar charplot:width +The number of columns to make the plot horizontally. +@end defvar -@item -Removing a couple extra files, most notably the documentation (but see -below). -@end itemize +@deffn Procedure plot! coords x-label y-label +@var{coords} is a list of pairs of x and y coordinates. @var{x-label} +and @var{y-label} are strings with which to label the x and y +axes.@refill -If you wish, you can see exactly what changes were done by reading the -shell script in the file @file{syncase.sh}. +Example: +@example +(require 'charplot) +@ftindex charplot +(set! charplot:height 19) +(set! charplot:width 45) -The two PostScript files were omitted in order to not burden the SLIB -distribution with them. If you do intend to use @code{syntax-case}, -however, you should get these files and print them out on a PostScript -printer. They are available with the original @code{syntax-case} -distribution by anonymous FTP in -@file{cs.indiana.edu:/pub/scheme/syntax-case}.@refill +(define (make-points n) + (if (zero? n) + '() + (cons (cons (/ n 6) (sin (/ n 6))) (make-points (1- n))))) -In order to use syntax-case from an interactive top level, execute: -@lisp -(require 'syntax-case) -(require 'repl) -(repl:top-level macro:eval) -@end lisp -See the section Repl (@xref{Repl}) for more information. +(plot! (make-points 37) "x" "Sin(x)") +@print{} +@group + Sin(x) ______________________________________________ + 1.25|- | + | | + 1|- **** | + | ** ** | + 750.0e-3|- * * | + | * * | + 500.0e-3|- * * | + | * | + 250.0e-3|- * | + | * * | + 0|-------------------*--------------------------| + | * | + -250.0e-3|- * * | + | * * | + -500.0e-3|- * | + | * * | + -750.0e-3|- * * | + | ** ** | + -1|- **** | + |____________:_____._____:_____._____:_________| + x 2 4 +@end group +@end example +@end deffn -To check operation of syntax-case get -@file{cs.indiana.edu:/pub/scheme/syntax-case}, and type -@lisp -(require 'syntax-case) -(syncase:sanity-check) -@end lisp -Beware that @code{syntax-case} takes a long time to load -- about 20s on -a SPARCstation SLC (with SCM) and about 90s on a Macintosh SE/30 (with -Gambit). +@node Root Finding, Commutative Rings, Plotting, Mathematical Packages +@section Root Finding -@subsection Notes +@code{(require 'root)} +@ftindex root -All R4RS syntactic forms are defined, including @code{delay}. Along -with @code{delay} are simple definitions for @code{make-promise} (into -which @code{delay} expressions expand) and @code{force}.@refill +@defun newtown:find-integer-root f df/dx x0 +Given integer valued procedure @var{f}, its derivative (with respect to +its argument) @var{df/dx}, and initial integer value @var{x0} for which +@var{df/dx}(@var{x0}) is non-zero, returns an integer @var{x} for which +@var{f}(@var{x}) is closer to zero than either of the integers adjacent +to @var{x}; or returns @code{#f} if such an integer can't be found. -@code{syntax-rules} and @code{with-syntax} (described in @cite{TR356}) -are defined.@refill +To find the closest integer to a given integers square root: -@code{syntax-case} is actually defined as a macro that expands into -calls to the procedure @code{syntax-dispatch} and the core form -@code{syntax-lambda}; do not redefine these names.@refill +@example +(define (integer-sqrt y) + (newton:find-integer-root + (lambda (x) (- (* x x) y)) + (lambda (x) (* 2 x)) + (ash 1 (quotient (integer-length y) 2)))) -Several other top-level bindings not documented in TR356 are created: -@itemize -@item the ``hooks'' in @file{hooks.ss} -@item the @code{build-} procedures in @file{output.ss} -@item @code{expand-syntax} (the expander) -@end itemize +(integer-sqrt 15) @result{} 4 +@end example +@end defun -The syntax of define has been extended to allow @code{(define @var{id})}, -which assigns @var{id} to some unspecified value.@refill +@defun integer-sqrt y +Given a non-negative integer @var{y}, returns the rounded square-root of +@var{y}. +@end defun -We have attempted to maintain R4RS compatibility where possible. The -incompatibilities should be confined to @file{hooks.ss}. Please let us -know if there is some incompatibility that is not flagged as such.@refill +@defun newton:find-root f df/dx x0 prec +Given real valued procedures @var{f}, @var{df/dx} of one (real) +argument, initial real value @var{x0} for which @var{df/dx}(@var{x0}) is +non-zero, and positive real number @var{prec}, returns a real @var{x} +for which @code{abs}(@var{f}(@var{x})) is less than @var{prec}; or +returns @code{#f} if such a real can't be found. -Send bug reports, comments, suggestions, and questions to Kent Dybvig -(dyb@@iuvax.cs.indiana.edu). +If @code{prec} is instead a negative integer, @code{newton:find-root} +returns the result of -@var{prec} iterations. +@end defun -@subsection Note from maintainer +@noindent +H. J. Orchard, @cite{The Laguerre Method for Finding the Zeros of +Polynomials}, IEEE Transactions on Circuits and Systems, Vol. 36, +No. 11, November 1989, pp 1377-1381. -Included with the @code{syntax-case} files was @file{structure.scm} -which defines a macro @code{define-structure}. There is no -documentation for this macro and it is not used by any code in SLIB. +@quotation +There are 2 errors in Orchard's Table II. Line k=2 for starting +value of 1000+j0 should have Z_k of 1.0475 + j4.1036 and line k=2 +for starting value of 0+j1000 should have Z_k of 1.0988 + j4.0833. +@end quotation -@node Fluid-Let, Yasos, Syntax-Case Macros, Macros -@section Fluid-Let -@code{(require 'fluid-let)} +@defun laguerre:find-root f df/dz ddf/dz^2 z0 prec +Given complex valued procedure @var{f} of one (complex) argument, its +derivative (with respect to its argument) @var{df/dx}, its second +derivative @var{ddf/dz^2}, initial complex value @var{z0}, and positive +real number @var{prec}, returns a complex number @var{z} for which +@code{magnitude}(@var{f}(@var{z})) is less than @var{prec}; or returns +@code{#f} if such a number can't be found. -@deffn Syntax fluid-let @code{(@var{bindings} @dots{})} @var{forms}@dots{} -@end deffn -@lisp -(fluid-let ((@var{variable} @var{init}) @dots{}) - @var{expression} @var{expression} @dots{}) -@end lisp +If @code{prec} is instead a negative integer, @code{laguerre:find-root} +returns the result of -@var{prec} iterations. +@end defun -The @var{init}s are evaluated in the current environment (in some -unspecified order), the current values of the @var{variable}s are saved, -the results are assigned to the @var{variable}s, the @var{expression}s -are evaluated sequentially in the current environment, the -@var{variable}s are restored to their original values, and the value of -the last @var{expression} is returned.@refill +@defun laguerre:find-polynomial-root deg f df/dz ddf/dz^2 z0 prec +Given polynomial procedure @var{f} of integer degree @var{deg} of one +argument, its derivative (with respect to its argument) @var{df/dx}, its +second derivative @var{ddf/dz^2}, initial complex value @var{z0}, and +positive real number @var{prec}, returns a complex number @var{z} for +which @code{magnitude}(@var{f}(@var{z})) is less than @var{prec}; or +returns @code{#f} if such a number can't be found. -The syntax of this special form is similar to that of @code{let}, but -@code{fluid-let} temporarily rebinds existing @var{variable}s. Unlike -@code{let}, @code{fluid-let} creates no new bindings; instead it -@emph{assigns} the values of each @var{init} to the binding (determined -by the rules of lexical scoping) of its corresponding -@var{variable}.@refill +If @code{prec} is instead a negative integer, +@code{laguerre:find-polynomial-root} returns the result of -@var{prec} +iterations. +@end defun +@node Commutative Rings, Determinant, Root Finding, Mathematical Packages +@section Commutative Rings -@node Yasos, , Fluid-Let, Macros -@section Yasos +Scheme provides a consistent and capable set of numeric functions. +Inexacts implement a field; integers a commutative ring (and Euclidean +domain). This package allows the user to use basic Scheme numeric +functions with symbols and non-numeric elements of commutative rings. -@c Much of the documentation in this section was written by Dave Love -@c (d.love@dl.ac.uk) -- don't blame Ken Dickey for its faults. -@c but we can blame him for not writing it! +@code{(require 'commutative-ring)} +@ftindex commutative-ring +@cindex ring, commutative -@code{(require 'oop)} or @code{(require 'yasos)} +The @dfn{commutative-ring} package makes @code{+}, @code{-}, @code{*}, +@code{/}, and @code{^} @dfn{careful} in the sense that any non-numeric +@cindex careful +arguments which it cannot reduce appear in the expression output. In +order to see what working with this package is like, self-set all the +single letter identifiers (to their corresponding symbols). -`Yet Another Scheme Object System' is a simple object system for Scheme -based on the paper by Norman Adams and Jonathan Rees: @cite{Object -Oriented Programming in Scheme}, Proceedings of the 1988 ACM Conference -on LISP and Functional Programming, July 1988 [ACM #552880].@refill +@example +(define a 'a) +@dots{} +(define z 'z) +@end example +Or just @code{(require 'self-set)}. Now for some sample expressions: -Another reference is: +@example +(* (+ a b) (+ a b)) @result{} (+ (* 2 a b) (^ a 2) (^ b 2)) +(* (+ a b) (- a b)) @result{} (- (^ a 2) (^ b 2)) +(* (- a b) (- a b)) @result{} (- (+ (^ a 2) (^ b 2)) (* 2 a b)) +(* (- a b) (+ a b)) @result{} (- (^ a 2) (^ b 2)) +(/ (+ a b) (+ c d)) @result{} (+ (/ a (+ c d)) (/ b (+ c d))) +(/ (+ a b) (- c d)) @result{} (+ (/ a (- c d)) (/ b (- c d))) +(/ (- a b) (- c d)) @result{} (- (/ a (- c d)) (/ b (- c d))) +(/ (- a b) (+ c d)) @result{} (- (/ a (+ c d)) (/ b (+ c d))) +(^ (+ a b) 3) @result{} (+ (* 3 a (^ b 2)) (* 3 b (^ a 2)) (^ a 3) (^ b 3)) +(^ (+ a 2) 3) @result{} (+ 8 (* a 12) (* (^ a 2) 6) (^ a 3)) +@end example -Ken Dickey. -@ifset html - -@end ifset -Scheming with Objects -@ifset html - -@end ifset -@cite{AI Expert} Volume 7, Number 10 (October 1992), pp. 24-33. +Use of this package is not restricted to simple arithmetic expressions: -@menu -* Yasos terms:: Definitions and disclaimer. -* Yasos interface:: The Yasos macros and procedures. -* Setters:: Dylan-like setters in Yasos. -* Yasos examples:: Usage of Yasos and setters. -@end menu +@example +(require 'determinant) -@node Yasos terms, Yasos interface, Yasos, Yasos -@subsection Terms +(determinant '((a b c) (d e f) (g h i))) @result{} +(- (+ (* a e i) (* b f g) (* c d h)) (* a f h) (* b d i) (* c e g)) +@end example -@table @asis -@item @dfn{Object} -Any Scheme data object. +The @dfn{commutative-ring} package differs from other extension +mechanisms in that it automatically, using properties true of all +commutative rings, simplifies sum and product expressions containing +non-numeric elements. One need only specify behavior for @code{+} or +@code{*} for cases where expressions involving objects reduce to numbers +or to expressions involving different non-numeric elements. + +Currently, only @code{+}, @code{-}, @code{*}, @code{/}, and @code{^} +support non-numeric elements. Expressions with @code{-} are converted +to equivalent expressions without @code{-}, so behavior for @code{-} is +not defined separately. @code{/} expressions are handled similarly. + +This list might be extended to include @code{quotient}, @code{modulo}, +@code{remainder}, @code{lcm}, and @code{gcd}; but these work only for +the more restrictive Euclidean (Unique Factorization) Domain. +@cindex Unique Factorization +@cindex Euclidean Domain + +@defun cring:define-rule op sub-op1 sub-op2 reduction +Defines a rule for the case when the operation represented by symbol +@var{op} is applied to lists whose @code{car}s are @var{sub-op1} and +@var{sub-op2}, respectively. The argument @var{reduction} is a +procedure accepting 2 arguments which will be lists whose @code{car}s +are @var{sub-op1} and @var{sub-op2}. + +@defunx cring:define-rule op sub-op1 'identity reduction +Defines a rule for the case when the operation represented by symbol +@var{op} is applied to a list whose @code{car} is @var{sub-op1}, and +some other argument. @var{Reduction} will be called with the list whose +@code{car} is @var{sub-op1} and some other argument. + +If @var{reduction} returns @code{#f}, the reduction has failed and other +reductions will be tried. If @var{reduction} returns a non-false value, +that value will replace the two arguments in arithmetic (@code{+}, +@code{-}, and @code{*}) calculations involving non-numeric elements. + +The operations @code{+} and @code{*} are assumed commutative; hence both +orders of arguments to @var{reduction} will be tried if necessary. + +The following rule is the built-in definition for distributing @code{*} +over @code{+}. -@item @dfn{Instance} -An instance of the OO system; an @dfn{object}. +@example +(cring:define-rule + '* '+ 'identity + (lambda (exp1 exp2) + (apply + (map (lambda (trm) (* trm exp2)) (cdr exp1)))))) +@end example +@end defun -@item @dfn{Operation} -A @var{method}. -@end table +@heading How to Create a Commutative Ring -@table @emph -@item Notes: -The object system supports multiple inheritance. An instance can -inherit from 0 or more ancestors. In the case of multiple inherited -operations with the same identity, the operation used is that from the -first ancestor which contains it (in the ancestor @code{let}). An -operation may be applied to any Scheme data object---not just instances. -As code which creates instances is just code, there are no @dfn{classes} -and no meta-@var{anything}. Method dispatch is by a procedure call a la -CLOS rather than by @code{send} syntax a la Smalltalk.@refill +The first step in creating your commutative ring is to write procedures +to create elements of the ring. A non-numeric element of the ring must +be represented as a list whose first element is a symbol or string. +This first element identifies the type of the object. A convenient and +clear convention is to make the type-identifying element be the same +symbol whose top-level value is the procedure to create it. -@item Disclaimer: -There are a number of optimizations which can be made. This -implementation is expository (although performance should be quite -reasonable). See the L&FP paper for some suggestions.@refill -@end table +@example +(define (n . list1) + (cond ((and (= 2 (length list1)) + (eq? (car list1) (cadr list1))) + 0) + ((not (term< (first list1) (last1 list1))) + (apply n (reverse list1))) + (else (cons 'n list1)))) + +(define (s x y) (n x y)) + +(define (m . list1) + (cond ((neq? (first list1) (term_min list1)) + (apply m (cyclicrotate list1))) + ((term< (last1 list1) (cadr list1)) + (apply m (reverse (cyclicrotate list1)))) + (else (cons 'm list1)))) +@end example +Define a procedure to multiply 2 non-numeric elements of the ring. +Other multiplicatons are handled automatically. Objects for which rules +have @emph{not} been defined are not changed. +@example +(define (n*n ni nj) + (let ((list1 (cdr ni)) (list2 (cdr nj))) + (cond ((null? (intersection list1 list2)) #f) + ((and (eq? (last1 list1) (first list2)) + (neq? (first list1) (last1 list2))) + (apply n (splice list1 list2))) + ((and (eq? (first list1) (first list2)) + (neq? (last1 list1) (last1 list2))) + (apply n (splice (reverse list1) list2))) + ((and (eq? (last1 list1) (last1 list2)) + (neq? (first list1) (first list2))) + (apply n (splice list1 (reverse list2)))) + ((and (eq? (last1 list1) (first list2)) + (eq? (first list1) (last1 list2))) + (apply m (cyclicsplice list1 list2))) + ((and (eq? (first list1) (first list2)) + (eq? (last1 list1) (last1 list2))) + (apply m (cyclicsplice (reverse list1) list2))) + (else #f)))) +@end example +Test the procedures to see if they work. +@example +;;; where cyclicrotate(list) is cyclic rotation of the list one step +;;; by putting the first element at the end +(define (cyclicrotate list1) + (append (rest list1) (list (first list1)))) +;;; and where term_min(list) is the element of the list which is +;;; first in the term ordering. +(define (term_min list1) + (car (sort list1 term<))) +(define (term< sym1 sym2) + (stringstring sym1) (symbol->string sym2))) +(define first car) +(define rest cdr) +(define (last1 list1) (car (last-pair list1))) +(define (neq? obj1 obj2) (not (eq? obj1 obj2))) +;;; where splice is the concatenation of list1 and list2 except that their +;;; common element is not repeated. +(define (splice list1 list2) + (cond ((eq? (last1 list1) (first list2)) + (append list1 (cdr list2))) + (else (error 'splice list1 list2)))) +;;; where cyclicsplice is the result of leaving off the last element of +;;; splice(list1,list2). +(define (cyclicsplice list1 list2) + (cond ((and (eq? (last1 list1) (first list2)) + (eq? (first list1) (last1 list2))) + (butlast (splice list1 list2) 1)) + (else (error 'cyclicsplice list1 list2)))) + +(N*N (S a b) (S a b)) @result{} (m a b) +@end example -@node Yasos interface, Setters, Yasos terms, Yasos -@subsection Interface +Then register the rule for multiplying type N objects by type N objects. -@deffn Syntax define-operation @code{(}opname self arg @dots{}@code{)} @var{default-body} -Defines a default behavior for data objects which don't handle the -operation @var{opname}. The default default behavior (for an empty -@var{default-body}) is to generate an error.@refill -@end deffn +@example +(cring:define-rule '* 'N 'N N*N)) +@end example -@deffn Syntax define-predicate opname? -Defines a predicate @var{opname?}, usually used for determining the -@dfn{type} of an object, such that @code{(@var{opname?} @var{object})} -returns @code{#t} if @var{object} has an operation @var{opname?} and -@code{#f} otherwise.@refill -@end deffn +Now we are ready to compute! -@deffn Syntax object @code{((@var{name} @var{self} @var{arg} @dots{}) @var{body})} @dots{} -Returns an object (an instance of the object system) with operations. -Invoking @code{(@var{name} @var{object} @var{arg} @dots{}} executes the -@var{body} of the @var{object} with @var{self} bound to @var{object} and -with argument(s) @var{arg}@dots{}.@refill -@end deffn +@example +(define (t) + (define detM + (+ (* (S g b) + (+ (* (S f d) + (- (* (S a f) (S d g)) (* (S a g) (S d f)))) + (* (S f f) + (- (* (S a g) (S d d)) (* (S a d) (S d g)))) + (* (S f g) + (- (* (S a d) (S d f)) (* (S a f) (S d d)))))) + (* (S g d) + (+ (* (S f b) + (- (* (S a g) (S d f)) (* (S a f) (S d g)))) + (* (S f f) + (- (* (S a b) (S d g)) (* (S a g) (S d b)))) + (* (S f g) + (- (* (S a f) (S d b)) (* (S a b) (S d f)))))) + (* (S g f) + (+ (* (S f b) + (- (* (S a d) (S d g)) (* (S a g) (S d d)))) + (* (S f d) + (- (* (S a g) (S d b)) (* (S a b) (S d g)))) + (* (S f g) + (- (* (S a b) (S d d)) (* (S a d) (S d b)))))) + (* (S g g) + (+ (* (S f b) + (- (* (S a f) (S d d)) (* (S a d) (S d f)))) + (* (S f d) + (- (* (S a b) (S d f)) (* (S a f) (S d b)))) + (* (S f f) + (- (* (S a d) (S d b)) (* (S a b) (S d d)))))))) + (* (S b e) (S c a) (S e c) + detM + )) +(pretty-print (t)) +@print{} +(- (+ (m a c e b d f g) + (m a c e b d g f) + (m a c e b f d g) + (m a c e b f g d) + (m a c e b g d f) + (m a c e b g f d)) + (* 2 (m a b e c) (m d f g)) + (* (m a c e b d) (m f g)) + (* (m a c e b f) (m d g)) + (* (m a c e b g) (m d f))) +@end example -@deffn Syntax object-with-ancestors @code{((}ancestor1 init1@code{)} @dots{}@code{)} operation @dots{} -A @code{let}-like form of @code{object} for multiple inheritance. It -returns an object inheriting the behaviour of @var{ancestor1} etc. An -operation will be invoked in an ancestor if the object itself does not -provide such a method. In the case of multiple inherited operations -with the same identity, the operation used is the one found in the first -ancestor in the ancestor list. -@end deffn +@node Determinant, , Commutative Rings, Mathematical Packages +@section Determinant -@deffn Syntax operate-as component operation self arg @dots{} -Used in an operation definition (of @var{self}) to invoke the -@var{operation} in an ancestor @var{component} but maintain the object's -identity. Also known as ``send-to-super''.@refill -@end deffn +@example +(require 'determinant) +(determinant '((1 2) (3 4))) @result{} -2 +(determinant '((1 2 3) (4 5 6) (7 8 9))) @result{} 0 +(determinant '((1 2 3 4) (5 6 7 8) (9 10 11 12))) @result{} 0 +@end example -@deffn Procedure print obj port -A default @code{print} operation is provided which is just @code{(format -@var{port} @var{obj})} (@xref{Format}) for non-instances and prints -@var{obj} preceded by @samp{#} for instances. -@end deffn -@defun size obj -The default method returns the number of elements in @var{obj} if it is -a vector, string or list, @code{2} for a pair, @code{1} for a character -and by default id an error otherwise. Objects such as collections -(@xref{Collections}) may override the default in an obvious way.@refill -@end defun +@node Database Packages, Other Packages, Mathematical Packages, Top +@chapter Database Packages +@menu +* Base Table:: +* Relational Database:: 'relational-database +* Weight-Balanced Trees:: 'wt-tree +@end menu +@node Base Table, Relational Database, Database Packages, Database Packages +@section Base Table +A base table implementation using Scheme association lists is available +as the value of the identifier @code{alist-table} after doing: +@code{(require 'alist-table)} +@ftindex alist-table -@node Setters, Yasos examples, Yasos interface, Yasos -@subsection Setters -@dfn{Setters} implement @dfn{generalized locations} for objects -associated with some sort of mutable state. A @dfn{getter} operation -retrieves a value from a generalized location and the corresponding -setter operation stores a value into the location. Only the getter is -named -- the setter is specified by a procedure call as below. (Dylan -uses special syntax.) Typically, but not necessarily, getters are -access operations to extract values from Yasos objects (@xref{Yasos}). -Several setters are predefined, corresponding to getters @code{car}, -@code{cdr}, @code{string-ref} and @code{vector-ref} e.g., @code{(setter -car)} is equivalent to @code{set-car!}. +Association list base tables are suitable for small databases and +support all Scheme types when temporary and readable/writeable Scheme +types when saved. I hope support for other base table implementations +will be added in the future. -This implementation of setters is similar to that in Dylan(TM) -(@cite{Dylan: An object-oriented dynamic language}, Apple Computer -Eastern Research and Technology). Common LISP provides similar -facilities through @code{setf}. +This rest of this section documents the interface for a base table +implementation from which the @ref{Relational Database} package +constructs a Relational system. It will be of interest primarily to +those wishing to port or write new base-table implementations. -@defun setter getter -Returns the setter for the procedure @var{getter}. E.g., since -@code{string-ref} is the getter corresponding to a setter which is -actually @code{string-set!}: -@example -(define foo "foo") -((setter string-ref) foo 0 #\F) ; set element 0 of foo -foo @result{} "Foo" -@end example -@end defun +All of these functions are accessed through a single procedure by +calling that procedure with the symbol name of the operation. A +procedure will be returned if that operation is supported and @code{#f} +otherwise. For example: -@deffn Syntax set place new-value -If @var{place} is a variable name, @code{set} is equivalent to -@code{set!}. Otherwise, @var{place} must have the form of a procedure -call, where the procedure name refers to a getter and the call indicates -an accessible generalized location, i.e., the call would return a value. -The return value of @code{set} is usually unspecified unless used with a -setter whose definition guarantees to return a useful value. @example -(set (string-ref foo 2) #\O) ; generalized location with getter -foo @result{} "FoO" -(set foo "foo") ; like set! -foo @result{} "foo" +@group +(require 'alist-table) +@ftindex alist-table +(define open-base (alist-table 'make-base)) +make-base @result{} *a procedure* +(define foo (alist-table 'foo)) +foo @result{} #f +@end group @end example -@end deffn -@deffn Procedure add-setter getter setter -Add procedures @var{getter} and @var{setter} to the (inaccessible) list -of valid setter/getter pairs. @var{setter} implements the store -operation corresponding to the @var{getter} access operation for the -relevant state. The return value is unspecified. -@end deffn +@defun make-base filename key-dimension column-types +Returns a new, open, low-level database (collection of tables) +associated with @var{filename}. This returned database has an empty +table associated with @var{catalog-id}. The positive integer +@var{key-dimension} is the number of keys composed to make a +@var{primary-key} for the catalog table. The list of symbols +@var{column-types} describes the types of each column for that table. +If the database cannot be created as specified, @code{#f} is returned. -@deffn Procedure remove-setter-for getter -Removes the setter corresponding to the specified @var{getter} from the -list of valid setters. The return value is unspecified. -@end deffn +Calling the @code{close-base} method on this database and possibly other +operations will cause @var{filename} to be written to. If +@var{filename} is @code{#f} a temporary, non-disk based database will be +created if such can be supported by the base table implelentation. +@end defun -@deffn Syntax define-access-operation getter-name -Shorthand for a Yasos @code{define-operation} defining an operation -@var{getter-name} that objects may support to return the value of some -mutable state. The default operation is to signal an error. The return -value is unspecified. -@end deffn +@defun open-base filename mutable +Returns an open low-level database associated with @var{filename}. If +@var{mutable?} is @code{#t}, this database will have methods capable of +effecting change to the database. If @var{mutable?} is @code{#f}, only +methods for inquiring the database will be available. If the database +cannot be opened as specified @code{#f} is returned. +Calling the @code{close-base} (and possibly other) method on a +@var{mutable?} database will cause @var{filename} to be written to. +@end defun +@defun write-base lldb filename +Causes the low-level database @var{lldb} to be written to +@var{filename}. If the write is successful, also causes @var{lldb} to +henceforth be associated with @var{filename}. Calling the +@code{close-database} (and possibly other) method on @var{lldb} may +cause @var{filename} to be written to. If @var{filename} is @code{#f} +this database will be changed to a temporary, non-disk based database if +such can be supported by the underlying base table implelentation. If +the operations completed successfully, @code{#t} is returned. +Otherwise, @code{#f} is returned. +@end defun +@defun sync-base lldb +Causes the file associated with the low-level database @var{lldb} to be +updated to reflect its current state. If the associated filename is +@code{#f}, no action is taken and @code{#f} is returned. If this +operation completes successfully, @code{#t} is returned. Otherwise, +@code{#f} is returned. +@end defun +@defun close-base lldb +Causes the low-level database @var{lldb} to be written to its associated +file (if any). If the write is successful, subsequent operations to +@var{lldb} will signal an error. If the operations complete +successfully, @code{#t} is returned. Otherwise, @code{#f} is returned. +@end defun -@node Yasos examples, , Setters, Yasos -@subsection Examples +@defun make-table lldb key-dimension column-types +Returns the @var{base-id} for a new base table, otherwise returns +@code{#f}. The base table can then be opened using @code{(open-table +@var{lldb} @var{base-id})}. The positive integer @var{key-dimension} is +the number of keys composed to make a @var{primary-key} for this table. +The list of symbols @var{column-types} describes the types of each +column. +@end defun -@lisp -(define-operation (print obj port) - (format port - (if (instance? obj) "#" "~s") - obj)) +@defvr Constant catalog-id +A constant @var{base-id} suitable for passing as a parameter to +@code{open-table}. @var{catalog-id} will be used as the base table for +the system catalog. +@end defvr -(define-operation (SIZE obj) - (cond - ((vector? obj) (vector-length obj)) - ((list? obj) (length obj)) - ((pair? obj) 2) - ((string? obj) (string-length obj)) - ((char? obj) 1) - (else - (error "Operation not supported: size" obj)))) +@defun open-table lldb base-id key-dimension column-types +Returns a @var{handle} for an existing base table in the low-level +database @var{lldb} if that table exists and can be opened in the mode +indicated by @var{mutable?}, otherwise returns @code{#f}. -(define-predicate cell?) -(define-operation (fetch obj)) -(define-operation (store! obj newValue)) +As with @code{make-table}, the positive integer @var{key-dimension} is +the number of keys composed to make a @var{primary-key} for this table. +The list of symbols @var{column-types} describes the types of each +column. +@end defun -(define (make-cell value) - (object - ((cell? self) #t) - ((fetch self) value) - ((store! self newValue) - (set! value newValue) - newValue) - ((size self) 1) - ((print self port) - (format port "#" (fetch self))))) +@defun kill-table lldb base-id key-dimension column-types +Returns @code{#t} if the base table associated with @var{base-id} was +removed from the low level database @var{lldb}, and @code{#f} otherwise. +@end defun -(define-operation (discard obj value) - (format #t "Discarding ~s~%" value)) +@defun make-keyifier-1 type +Returns a procedure which accepts a single argument which must be of +type @var{type}. This returned procedure returns an object suitable for +being a @var{key} argument in the functions whose descriptions follow. -(define (make-filtered-cell value filter) - (object-with-ancestors ((cell (make-cell value))) - ((store! self newValue) - (if (filter newValue) - (store! cell newValue) - (discard self newValue))))) +Any 2 arguments of the supported type passed to the returned function +which are not @code{equal?} must result in returned values which are not +@code{equal?}. +@end defun -(define-predicate array?) -(define-operation (array-ref array index)) -(define-operation (array-set! array index value)) +@defun make-list-keyifier key-dimension types +The list of symbols @var{types} must have at least @var{key-dimension} +elements. Returns a procedure which accepts a list of length +@var{key-dimension} and whose types must corresopond to the types named +by @var{types}. This returned procedure combines the elements of its +list argument into an object suitable for being a @var{key} argument in +the functions whose descriptions follow. -(define (make-array num-slots) - (let ((anArray (make-vector num-slots))) - (object - ((array? self) #t) - ((size self) num-slots) - ((array-ref self index) (vector-ref anArray index)) - ((array-set! self index newValue) (vector-set! anArray index newValue)) - ((print self port) (format port "#" (size self)))))) +Any 2 lists of supported types (which must at least include symbols and +non-negative integers) passed to the returned function which are not +@code{equal?} must result in returned values which are not +@code{equal?}. +@end defun -(define-operation (position obj)) -(define-operation (discarded-value obj)) +@defun make-key-extractor key-dimension types column-number +Returns a procedure which accepts objects produced by application of the +result of @code{(make-list-keyifier @var{key-dimension} @var{types})}. +This procedure returns a @var{key} which is @code{equal?} to the +@var{column-number}th element of the list which was passed to create +@var{combined-key}. The list @var{types} must have at least +@var{key-dimension} elements. +@end defun -(define (make-cell-with-history value filter size) - (let ((pos 0) (most-recent-discard #f)) - (object-with-ancestors - ((cell (make-filtered-call value filter)) - (sequence (make-array size))) - ((array? self) #f) - ((position self) pos) - ((store! self newValue) - (operate-as cell store! self newValue) - (array-set! self pos newValue) - (set! pos (+ pos 1))) - ((discard self value) - (set! most-recent-discard value)) - ((discarded-value self) most-recent-discard) - ((print self port) - (format port "#" (fetch self)))))) +@defun make-key->list key-dimension types +Returns a procedure which accepts objects produced by application of the +result of @code{(make-list-keyifier @var{key-dimension} @var{types})}. +This procedure returns a list of @var{key}s which are elementwise +@code{equal?} to the list which was passed to create @var{combined-key}. +@end defun -(define-access-operation fetch) -(add-setter fetch store!) -(define foo (make-cell 1)) -(print foo #f) -@result{} "#" -(set (fetch foo) 2) -@result{} -(print foo #f) -@result{} "#" -(fetch foo) -@result{} 2 -@end lisp +@noindent +In the following functions, the @var{key} argument can always be assumed +to be the value returned by a call to a @emph{keyify} routine. -@node Numerics, Procedures, Macros, Top -@chapter Numerics +@noindent +@cindex match-key +@cindex match +@cindex wild-card +In contrast, a @var{match-key} argument is a list of length equal to the +number of primary keys. The @var{match-key} restricts the actions of +the table command to those records whose primary keys all satisfy the +corresponding element of the @var{match-key} list. +The elements and their actions are: -@menu -* Bit-Twiddling:: 'logical -* Modular Arithmetic:: 'modular -* Prime Testing and Generation:: 'primes -* Prime Factorization:: 'factor -* Random Numbers:: 'random -* Cyclic Checksum:: 'make-crc -* Plotting:: 'charplot -* Root Finding:: -@end menu +@quotation +@table @asis +@item @code{#f} +The false value matches any key in the corresponding position. +@item an object of type procedure +This procedure must take a single argument, the key in the corresponding +position. Any key for which the procedure returns a non-false value is +a match; Any key for which the procedure returns a @code{#f} is not. +@item other values +Any other value matches only those keys @code{equal?} to it. +@end table +@end quotation +@defun for-each-key handle procedure match-key +Calls @var{procedure} once with each @var{key} in the table opened in +@var{handle} which satisfies @var{match-key} in an unspecified order. +An unspecified value is returned. +@end defun -@node Bit-Twiddling, Modular Arithmetic, Numerics, Numerics -@section Bit-Twiddling +@defun map-key handle procedure match-key +Returns a list of the values returned by calling @var{procedure} once +with each @var{key} in the table opened in @var{handle} which satisfies +@var{match-key} in an unspecified order. +@end defun -@code{(require 'logical)} +@defun ordered-for-each-key handle procedure match-key +Calls @var{procedure} once with each @var{key} in the table opened in +@var{handle} which satisfies @var{match-key} in the natural order for +the types of the primary key fields of that table. An unspecified value +is returned. +@end defun -The bit-twiddling functions are made available through the use of the -@code{logical} package. @code{logical} is loaded by inserting -@code{(require 'logical)} before the code that uses these -functions.@refill +@defun delete* handle match-key +Removes all rows which satisfy @var{match-key} from the table opened in +@var{handle}. An unspecified value is returned. +@end defun -@defun logand n1 n1 -Returns the integer which is the bit-wise AND of the two integer -arguments. +@defun present? handle key +Returns a non-@code{#f} value if there is a row associated with +@var{key} in the table opened in @var{handle} and @code{#f} otherwise. +@end defun -Example: -@lisp -(number->string (logand #b1100 #b1010) 2) - @result{} "1000" -@end lisp +@defun delete handle key +Removes the row associated with @var{key} from the table opened in +@var{handle}. An unspecified value is returned. @end defun -@defun logior n1 n2 -Returns the integer which is the bit-wise OR of the two integer -arguments. +@defun make-getter key-dimension types +Returns a procedure which takes arguments @var{handle} and @var{key}. +This procedure returns a list of the non-primary values of the relation +(in the base table opened in @var{handle}) whose primary key is +@var{key} if it exists, and @code{#f} otherwise. +@end defun -Example: -@lisp -(number->string (logior #b1100 #b1010) 2) - @result{} "1110" -@end lisp +@defun make-putter key-dimension types +Returns a procedure which takes arguments @var{handle} and @var{key} and +@var{value-list}. This procedure associates the primary key @var{key} +with the values in @var{value-list} (in the base table opened in +@var{handle}) and returns an unspecified value. @end defun -@defun logxor n1 n2 -Returns the integer which is the bit-wise XOR of the two integer -arguments. +@defun supported-type? symbol +Returns @code{#t} if @var{symbol} names a type allowed as a column value +by the implementation, and @code{#f} otherwise. At a minimum, an +implementation must support the types @code{integer}, @code{symbol}, +@code{string}, @code{boolean}, and @code{base-id}. +@end defun + +@defun supported-key-type? symbol +Returns @code{#t} if @var{symbol} names a type allowed as a key value by +the implementation, and @code{#f} otherwise. At a minimum, an +implementation must support the types @code{integer}, and @code{symbol}. +@end defun + +@table @code +@item integer +Scheme exact integer. +@item symbol +Scheme symbol. +@item boolean +@code{#t} or @code{#f}. +@item base-id +Objects suitable for passing as the @var{base-id} parameter to +@code{open-table}. The value of @var{catalog-id} must be an acceptable +@code{base-id}. +@end table -Example: -@lisp -(number->string (logxor #b1100 #b1010) 2) - @result{} "110" -@end lisp -@end defun +@node Relational Database, Weight-Balanced Trees, Base Table, Database Packages +@section Relational Database -@defun lognot n -Returns the integer which is the 2s-complement of the integer argument. +@code{(require 'relational-database)} +@ftindex relational-database -Example: -@lisp -(number->string (lognot #b10000000) 2) - @result{} "-10000001" -(number->string (lognot #b0) 2) - @result{} "-1" -@end lisp -@end defun +This package implements a database system inspired by the Relational +Model (@cite{E. F. Codd, A Relational Model of Data for Large Shared +Data Banks}). An SLIB relational database implementation can be created +from any @ref{Base Table} implementation. -@defun logtest j k -@example -(logtest j k) @equiv{} (not (zero? (logand j k))) +@menu +* Motivations:: Database Manifesto +* Creating and Opening Relational Databases:: +* Relational Database Operations:: +* Table Operations:: +* Catalog Representation:: +* Unresolved Issues:: +* Database Utilities:: 'database-utilities +@end menu -(logtest #b0100 #b1011) @result{} #f -(logtest #b0100 #b0111) @result{} #t -@end example -@end defun +@node Motivations, Creating and Opening Relational Databases, Relational Database, Relational Database +@subsection Motivations -@defun logbit? index j -@example -(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j) +Most nontrivial programs contain databases: Makefiles, configure +scripts, file backup, calendars, editors, source revision control, CAD +systems, display managers, menu GUIs, games, parsers, debuggers, +profilers, and even error reporting are all rife with databases. Coding +databases is such a common activity in programming that many may not be +aware of how often they do it. -(logbit? 0 #b1101) @result{} #t -(logbit? 1 #b1101) @result{} #f -(logbit? 2 #b1101) @result{} #t -(logbit? 3 #b1101) @result{} #t -(logbit? 4 #b1101) @result{} #f -@end example -@end defun +A database often starts as a dispatch in a program. The author, perhaps +because of the need to make the dispatch configurable, the need for +correlating dispatch in other routines, or because of changes or growth, +devises a data structure to contain the information, a routine for +interpreting that data structure, and perhaps routines for augmenting +and modifying the stored data. The dispatch must be converted into this +form and tested. -@defun ash int count -Returns an integer equivalent to -@code{(inexact->exact (floor (* @var{int} (expt 2 @var{count}))))}.@refill +The programmer may need to devise an interactive program for enabling +easy examination and modification of the information contained in this +database. Often, in an attempt to foster modularity and avoid delays in +release, intermediate file formats for the database information are +devised. It often turns out that users prefer modifying these +intermediate files with a text editor to using the interactive program +in order to do operations (such as global changes) not forseen by the +program's author. -Example: -@lisp -(number->string (ash #b1 3) 2) - @result{} "1000" -(number->string (ash #b1010 -1) 2) - @result{} "101" -@end lisp -@end defun +In order to address this need, the concientous software engineer may +even provide a scripting language to allow users to make repetitive +database changes. Users will grumble that they need to read a large +manual and learn yet another programming language (even if it +@emph{almost} has language "xyz" syntax) in order to do simple +configuration. -@defun logcount n -Returns the number of bits in integer @var{n}. If integer is positive, -the 1-bits in its binary representation are counted. If negative, the -0-bits in its two's-complement binary representation are counted. If 0, -0 is returned. +All of these facilities need to be designed, coded, debugged, +documented, and supported; often causing what was very simple in concept +to become a major developement project. -Example: -@lisp -(logcount #b10101010) - @result{} 4 -(logcount 0) - @result{} 0 -(logcount -2) - @result{} 1 -@end lisp -@end defun +This view of databases just outlined is somewhat the reverse of the view +of the originators of the @dfn{Relational Model} of database +abstraction. The relational model was devised to unify and allow +interoperation of large multi-user databases running on diverse +platforms. A fairly general purpose "Comprehensive Language" for +database manipulations is mandated (but not specified) as part of the +relational model for databases. -@defun integer-length n -Returns the number of bits neccessary to represent @var{n}. +One aspect of the Relational Model of some importance is that the +"Comprehensive Language" must be expressible in some form which can be +stored in the database. This frees the programmer from having to make +programs data-driven in order to use a database. -Example: -@lisp -(integer-length #b10101010) - @result{} 8 -(integer-length 0) - @result{} 0 -(integer-length #b1111) - @result{} 4 -@end lisp -@end defun +This package includes as one of its basic supported types Scheme +@dfn{expression}s. This type allows expressions as defined by the +Scheme standards to be stored in the database. Using @code{slib:eval} +retrieved expressions can be evaluated (in the top-level environment). +Scheme's @code{lambda} facilitates closure of environments, modularity, +etc. so that procedures (which could not be stored directly most +databases) can still be effectively retrieved. Since @code{slib:eval} +evaluates expressions in the top-level environment, built-in and user +defined procedures can be easily accessed by name. -@defun integer-expt n k -Returns @var{n} raised to the non-negative integer exponent @var{k}. +This package's purpose is to standardize (through a common interface) +database creation and usage in Scheme programs. The relational model's +provision for inclusion of language expressions as data as well as the +description (in tables, of course) of all of its tables assures that +relational databases are powerful enough to assume the roles currently +played by thousands of ad-hoc routines and data formats. -Example: -@lisp -(integer-expt 2 5) - @result{} 32 -(integer-expt -3 3) - @result{} -27 -@end lisp -@end defun +@noindent +Such standardization to a relational-like model brings many benefits: -@defun bit-extract n start end -Returns the integer composed of the @var{start} (inclusive) through -@var{end} (exclusive) bits of @var{n}. The @var{start}th bit becomes -the 0-th bit in the result.@refill +@itemize @bullet +@item +Tables, fields, domains, and types can be dealt with by name in +programs. +@item +The underlying database implementation can be changed (for +performance or other reasons) by changing a single line of code. +@item +The formats of tables can be easily extended or changed without +altering code. +@item +Consistency checks are specified as part of the table descriptions. +Changes in checks need only occur in one place. +@item +All the configuration information which the developer wishes to group +together is easily grouped, without needing to change programs aware of +only some of these tables. +@item +Generalized report generators, interactive entry programs, and other +database utilities can be part of a shared library. The burden of +adding configurability to a program is greatly reduced. +@item +Scheme is the "comprehensive language" for these databases. Scripting +for configuration no longer needs to be in a separate language with +additional documentation. +@item +Scheme's latent types mesh well with the strict typing and logical +requirements of the relational model. +@item +Portable formats allow easy interchange of data. The included table +descriptions help prevent misinterpretation of format. +@end itemize -Example: -@lisp -(number->string (bit-extract #b1101101010 0 4) 2) - @result{} "1010" -(number->string (bit-extract #b1101101010 4 9) 2) - @result{} "10110" -@end lisp -@end defun +@node Creating and Opening Relational Databases, Relational Database Operations, Motivations, Relational Database +@subsection Creating and Opening Relational Databases +@defun make-relational-system base-table-implementation -@node Modular Arithmetic, Prime Testing and Generation, Bit-Twiddling, Numerics -@section Modular Arithmetic +Returns a procedure implementing a relational database using the +@var{base-table-implementation}. -@code{(require 'modular)} +All of the operations of a base table implementation are accessed +through a procedure defined by @code{require}ing that implementation. +Similarly, all of the operations of the relational database +implementation are accessed through the procedure returned by +@code{make-relational-system}. For instance, a new relational database +could be created from the procedure returned by +@code{make-relational-system} by: -@defun extended-euclid n1 n2 -Returns a list of 3 integers @code{(d x y)} such that d = gcd(@var{n1}, -@var{n2}) = @var{n1} * x + @var{n2} * y.@refill +@example +(require 'alist-table) +@ftindex alist-table +(define relational-alist-system + (make-relational-system alist-table)) +(define create-alist-database + (relational-alist-system 'create-database)) +(define my-database + (create-alist-database "mydata.db")) +@end example @end defun -@defun symmetric:modulus n -Returns @code{(quotient (+ -1 n) -2)} for positive odd integer @var{n}. -@end defun +@noindent +What follows are the descriptions of the methods available from +relational system returned by a call to @code{make-relational-system}. -@defun modulus->integer modulus -Returns the non-negative integer characteristic of the ring formed when -@var{modulus} is used with @code{modular:} procedures. +@defun create-database filename + +Returns an open, nearly empty relational database associated with +@var{filename}. The only tables defined are the system catalog and +domain table. Calling the @code{close-database} method on this database +and possibly other operations will cause @var{filename} to be written +to. If @var{filename} is @code{#f} a temporary, non-disk based database +will be created if such can be supported by the underlying base table +implelentation. If the database cannot be created as specified +@code{#f} is returned. For the fields and layout of descriptor tables, +@xref{Catalog Representation} @end defun -@defun modular:normalize modulus n -Returns the integer @code{(modulo @var{n} (modulus->integer -@var{modulus}))} in the representation specified by @var{modulus}. +@defun open-database filename mutable? + +Returns an open relational database associated with @var{filename}. If +@var{mutable?} is @code{#t}, this database will have methods capable of +effecting change to the database. If @var{mutable?} is @code{#f}, only +methods for inquiring the database will be available. Calling the +@code{close-database} (and possibly other) method on a @var{mutable?} +database will cause @var{filename} to be written to. If the database +cannot be opened as specified @code{#f} is returned. @end defun -@noindent -The rest of these functions assume normalized arguments; That is, the -arguments are constrained by the following table: +@node Relational Database Operations, Table Operations, Creating and Opening Relational Databases, Relational Database +@subsection Relational Database Operations @noindent -For all of these functions, if the first argument (@var{modulus}) is: -@table @code -@item positive? -Work as before. The result is between 0 and @var{modulus}. - -@item zero? -The arguments are treated as integers. An integer is returned. - -@item negative? -The arguments and result are treated as members of the integers modulo -@code{(+ 1 (* -2 @var{modulus}))}, but with @dfn{symmetric} -representation; i.e. @code{(<= (- @var{modulus}) @var{n} -@var{modulus})}. -@end table +These are the descriptions of the methods available from an open +relational database. A method is retrieved from a database by calling +the database with the symbol name of the operation. For example: -@noindent -If all the arguments are fixnums the computation will use only fixnums. +@example +(define my-database + (create-alist-database "mydata.db")) +(define telephone-table-desc + ((my-database 'create-table) 'telephone-table-desc)) +@end example -@defun modular:invertable? modulus k -Returns @code{#t} if there exists an integer n such that @var{k} * n -@equiv{} 1 mod @var{modulus}, and @code{#f} otherwise. +@defun close-database +Causes the relational database to be written to its associated file (if +any). If the write is successful, subsequent operations to this +database will signal an error. If the operations completed +successfully, @code{#t} is returned. Otherwise, @code{#f} is returned. @end defun -@defun modular:invert modulus k2 -Returns an integer n such that 1 = (n * @var{k2}) mod @var{modulus}. If -@var{k2} has no inverse mod @var{modulus} an error is signaled. +@defun write-database filename +Causes the relational database to be written to @var{filename}. If the +write is successful, also causes the database to henceforth be +associated with @var{filename}. Calling the @code{close-database} (and +possibly other) method on this database will cause @var{filename} to be +written to. If @var{filename} is @code{#f} this database will be +changed to a temporary, non-disk based database if such can be supported +by the underlying base table implelentation. If the operations +completed successfully, @code{#t} is returned. Otherwise, @code{#f} is +returned. @end defun -@defun modular:negate modulus k2 -Returns (@minus{}@var{k2}) mod @var{modulus}. +@defun table-exists? table-name +Returns @code{#t} if @var{table-name} exists in the system catalog, +otherwise returns @code{#f}. @end defun -@defun modular:+ modulus k2 k3 -Returns (@var{k2} + @var{k3}) mod @var{modulus}. +@defun open-table table-name mutable? +Returns a @dfn{methods} procedure for an existing relational table in +this database if it exists and can be opened in the mode indicated by +@var{mutable?}, otherwise returns @code{#f}. @end defun -@defun modular:@minus{} modulus k2 k3 -Returns (@var{k2} @minus{} @var{k3}) mod @var{modulus}. +@noindent +These methods will be present only in databases which are +@var{mutable?}. + +@defun delete-table table-name +Removes and returns the @var{table-name} row from the system catalog if +the table or view associated with @var{table-name} gets removed from the +database, and @code{#f} otherwise. @end defun -@defun modular:* modulus k2 k3 -Returns (@var{k2} * @var{k3}) mod @var{modulus}. +@defun create-table table-desc-name +Returns a methods procedure for a new (open) relational table for +describing the columns of a new base table in this database, otherwise +returns @code{#f}. For the fields and layout of descriptor tables, +@xref{Catalog Representation}. -The Scheme code for @code{modular:*} with negative @var{modulus} is not -completed for fixnum-only implementations. +@defunx create-table table-name table-desc-name +Returns a methods procedure for a new (open) relational table with +columns as described by @var{table-desc-name}, otherwise returns +@code{#f}. @end defun -@defun modular:expt modulus k2 k3 -Returns (@var{k2} ^ @var{k3}) mod @var{modulus}. +@defun create-view ?? +@defunx project-table ?? +@defunx restrict-table ?? +@defunx cart-prod-tables ?? +Not yet implemented. @end defun +@node Table Operations, Catalog Representation, Relational Database Operations, Relational Database +@subsection Table Operations -@node Prime Testing and Generation, Prime Factorization, Modular Arithmetic, Numerics -@section Prime Testing and Generation - -@code{(require 'primes)} - -This package tests and generates prime numbers. The strategy used is -as follows: - -@itemize -@item -First, use trial division by small primes (primes less than 1000) to -quickly weed out composites with small factors. As a side benefit, this -makes the test precise for numbers up to one million. -@item -Second, apply the Miller-Rabin primality test to detect (with high -probability) any remaining composites. -@end itemize - -The Miller-Rabin test is a Monte-Carlo test---in other words, it's fast -and it gets the right answer with high probability. For a candidate -that @emph{is} prime, the Miller-Rabin test is certain to report -"prime"; it will never report "composite". However, for a candidate -that is composite, there is a (small) probability that the Miller-Rabin -test will erroneously report "prime". This probability can be made -arbitarily small by adjusting the number of iterations of the -Miller-Rabin test. +@noindent +These are the descriptions of the methods available from an open +relational table. A method is retrieved from a table by calling +the table with the symbol name of the operation. For example: -@defun probably-prime? candidate -@defunx probably-prime? candidate iter -Returns @code{#t} if @code{candidate} is probably prime. The optional -parameter @code{iter} controls the number of iterations of the -Miller-Rabin test. The probability of a composite candidate being -mistaken for a prime is at most @code{(1/4)^iter}. The default value of -@code{iter} is 15, which makes the probability less than 1 in 10^9. +@example +@group +(define telephone-table-desc + ((my-database 'create-table) 'telephone-table-desc)) +(require 'common-list-functions) +(define ndrp (telephone-table-desc 'row:insert)) +(ndrp '(1 #t name #f string)) +(ndrp '(2 #f telephone + (lambda (d) + (and (string? d) (> (string-length d) 2) + (every + (lambda (c) + (memv c '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 + #\+ #\( #\ #\) #\-))) + (string->list d)))) + string)) +@end group +@end example -@end defun +@noindent +Some operations described below require primary key arguments. Primary +keys arguments are denoted @var{key1} @var{key2} @dots{}. It is an +error to call an operation for a table which takes primary key arguments +with the wrong number of primary keys for that table. -@defun primes< start count -@defunx primes< start count iter -@defunx primes> start count -@defunx primes> start count iter -Returns a list of the first @code{count} odd probable primes less (more) -than or equal to @code{start}. The optional parameter @code{iter} -controls the number of iterations of the Miller-Rabin test for each -candidate. The probability of a composite candidate being mistaken for -a prime is at most @code{(1/4)^iter}. The default value of @code{iter} -is 15, which makes the probability less than 1 in 10^9. +@noindent +The term @dfn{row} used below refers to a Scheme list of values (one for +each column) in the order specified in the descriptor (table) for this +table. Missing values appear as @code{#f}. Primary keys must not +be missing. -@end defun +@defun get column-name +Returns a procedure of arguments @var{key1} @var{key2} @dots{} which +returns the value for the @var{column-name} column of the row associated +with primary keys @var{key1}, @var{key2} @dots{} if that row exists in +the table, or @code{#f} otherwise. -@menu -* The Miller-Rabin Test:: How the Miller-Rabin test works -@end menu +@example +((plat 'get 'processor) 'djgpp) @result{} i386 +((plat 'get 'processor) 'be-os) @result{} #f +@end example -@node The Miller-Rabin Test, , Prime Testing and Generation, Prime Testing and Generation -@subsection Theory +@defunx get* column-name +Returns a procedure of optional arguments @var{match-key1} @dots{} which +returns a list of the values for the specified column for all rows in +this table. The optional @var{match-key1} @dots{} arguments restrict +actions to a subset of the table. See the match-key description below +for details. -Rabin and Miller's result can be summarized as follows. Let @code{p} -(the candidate prime) be any odd integer greater than 2. Let @code{b} -(the "base") be an integer in the range @code{2 ... p-1}. There is a -fairly simple Boolean function---call it @code{C}, for -"Composite"---with the following properties: -@itemize +@example +((plat 'get* 'processor)) @result{} +(i386 8086 i386 8086 i386 i386 8086 m68000 + m68000 m68000 m68000 m68000 powerpc) -@item -If @code{p} is prime, @code{C(p, b)} is false for all @code{b} in the range -@code{2 ... p-1}. +((plat 'get* 'processor) #f) @result{} +(i386 8086 i386 8086 i386 i386 8086 m68000 + m68000 m68000 m68000 m68000 powerpc) -@item -If @code{p} is composite, @code{C(p, b)} is false for at most 1/4 of all -@code{b} in the range @code{ 2 ... p-1}. (If the test fails for base -@code{b}, @code{p} is called a @emph{strong pseudo-prime to base -@code{b}}.) +(define (a-key? key) + (char=? #\a (string-ref (symbol->string key) 0))) -@end itemize -For details of @code{C}, and why it fails for at most 1/4 of the -potential bases, please consult a book on number theory or cryptography -such as "A Course in Number Theory and Cryptography" by Neal Koblitz, -published by Springer-Verlag 1994. +((plat 'get* 'processor) a-key?) @result{} +(m68000 m68000 m68000 m68000 m68000 powerpc) -There is nothing probablistic about this result. It's true for all -@code{p}. If we had time to test @code{(1/4)p + 1} different bases, we -could definitively determine the primality of @code{p}. For large -candidates, that would take much too long---much longer than the simple -approach of dividing by all numbers up to @code{sqrt(p)}. This is -where probability enters the picture. +((plat 'get* 'name) a-key?) @result{} +(atari-st-turbo-c atari-st-gcc amiga-sas/c-5.10 + amiga-aztec amiga-dice-c aix) +@end example +@end defun -Suppose we have some candidate prime @code{p}. Pick a random integer -@code{b} in the range @code{2 ... p-1}. Compute @code{C(p,b)}. If -@code{p} is prime, the result will certainly be false. If @code{p} is -composite, the probability is at most 1/4 that the result will be false -(demonstrating that @code{p} is a strong pseudoprime to base @code{b}). -The test can be repeated with other random bases. If @code{p} is prime, -each test is certain to return false. If @code{p} is composite, the -probability of @code{C(p,b)} returning false is at most 1/4 for each -test. Since the @code{b} are chosen at random, the tests outcomes are -independent. So if @code{p} is composite and the test is repeated, say, -15 times, the probability of it returning false all fifteen times is at -most (1/4)^15, or about 10^-9. If the test is repeated 30 times, the -probability of failure drops to at most 8.3e-25. +@defun row:retrieve +Returns a procedure of arguments @var{key1} @var{key2} @dots{} which +returns the row associated with primary keys @var{key1}, @var{key2} +@dots{} if it exists, or @code{#f} otherwise. -Rabin and Miller's result holds for @emph{all} candidates @code{p}. -However, if the candidate @code{p} is picked at random, the probability -of the Miller-Rabin test failing is much less than the computed bound. -This is because, for @emph{most} composite numbers, the fraction of -bases that cause the test to fail is much less than 1/4. For example, -if you pick a random odd number less than 1000 and apply the -Miller-Rabin test with only 3 random bases, the computed failure bound -is (1/4)^3, or about 1.6e-2. However, the actual probability of failure -is much less---about 7.2e-5. If you accidentally pick 703 to test for -primality, the probability of failure is (161/703)^3, or about 1.2e-2, -which is almost as high as the computed bound. This is because 703 is a -strong pseudoprime to 161 bases. But if you pick at random there is -only a small chance of picking 703, and no other number less than 1000 -has that high a percentage of pseudoprime bases. +@example +((plat 'row:retrieve) 'linux) @result{} (linux i386 linux gcc) +((plat 'row:retrieve) 'multics) @result{} #f +@end example -The Miller-Rabin test is sometimes used in a slightly different fashion, -where it can, at least in principle, cause problems. The weaker version -uses small prime bases instead of random bases. If you are picking -candidates at random and testing for primality, this works well since -very few composites are strong pseudo-primes to small prime bases. (For -example, there is only one composite less than 2.5e10 that is a strong -pseudo-prime to the bases 2, 3, 5, and 7.) The problem with this -approach is that once a candidate has been picked, the test is -deterministic. This distinction is subtle, but real. With the -randomized test, for @emph{any} candidate you pick---even if your -candidate-picking procedure is strongly biased towards troublesome -numbers, the test will work with high probability. With the -deterministic version, for any particular candidate, the test will -either work (with probability 1), or fail (with probability 1). It -won't fail for very many candidates, but that won't be much consolation -if your candidate-picking procedure is somehow biased toward troublesome -numbers. +@defunx row:retrieve* +Returns a procedure of optional arguments @var{match-key1} @dots{} which +returns a list of all rows in this table. The optional @var{match-key1} +@dots{} arguments restrict actions to a subset of the table. See the +match-key description below for details. +@end defun +@example +((plat 'row:retrieve*) a-key?) @result{} +((atari-st-turbo-c m68000 atari turbo-c) + (atari-st-gcc m68000 atari gcc) + (amiga-sas/c-5.10 m68000 amiga sas/c) + (amiga-aztec m68000 amiga aztec) + (amiga-dice-c m68000 amiga dice-c) + (aix powerpc aix -)) +@end example -@node Prime Factorization, Random Numbers, Prime Testing and Generation, Numerics -@section Prime Factorization +@defun row:remove +Returns a procedure of arguments @var{key1} @var{key2} @dots{} which +removes and returns the row associated with primary keys @var{key1}, +@var{key2} @dots{} if it exists, or @code{#f} otherwise. -@code{(require 'factor)} +@defunx row:remove* +Returns a procedure of optional arguments @var{match-key1} @dots{} which +removes and returns a list of all rows in this table. The optional +@var{match-key1} @dots{} arguments restrict actions to a subset of the +table. See the match-key description below for details. +@end defun +@defun row:delete +Returns a procedure of arguments @var{key1} @var{key2} @dots{} which +deletes the row associated with primary keys @var{key1}, @var{key2} +@dots{} if it exists. The value returned is unspecified. -@defun factor k -Returns a list of the prime factors of @var{k}. The order of the -factors is unspecified. In order to obtain a sorted list do -@code{(sort! (factor k) <)}.@refill +@defunx row:delete* +Returns a procedure of optional arguments @var{match-key1} @dots{} which +Deletes all rows from this table. The optional @var{match-key1} @dots{} +arguments restrict deletions to a subset of the table. See the +match-key description below for details. The value returned is +unspecified. The descriptor table and catalog entry for this table are +not affected. @end defun -@emph{Note:} The rest of these procedures implement the Solovay-Strassen -primality test. This test has been superseeded by the faster -@xref{Prime Testing and Generation, probably-prime?}. However these are -left here as they take up little space and may be of use to an -implementation without bignums. +@defun row:update +Returns a procedure of one argument, @var{row}, which adds the row, +@var{row}, to this table. If a row for the primary key(s) specified by +@var{row} already exists in this table, it will be overwritten. The +value returned is unspecified. -See Robert Solovay and Volker Strassen, @cite{A Fast Monte-Carlo Test -for Primality}, SIAM Journal on Computing, 1977, pp 84-85. +@defunx row:update* +Returns a procedure of one argument, @var{rows}, which adds each row in +the list of rows, @var{rows}, to this table. If a row for the primary +key specified by an element of @var{rows} already exists in this table, +it will be overwritten. The value returned is unspecified. +@end defun -@defun jacobi-symbol p q -Returns the value (+1, @minus{}1, or 0) of the Jacobi-Symbol of exact -non-negative integer @var{p} and exact positive odd integer -@var{q}.@refill +@defun row:insert +Adds the row @var{row} to this table. If a row for the primary key(s) +specified by @var{row} already exists in this table an error is +signaled. The value returned is unspecified. + +@defunx row:insert* +Returns a procedure of one argument, @var{rows}, which adds each row in +the list of rows, @var{rows}, to this table. If a row for the primary +key specified by an element of @var{rows} already exists in this table, +an error is signaled. The value returned is unspecified. @end defun -@defun prime? p -Returns @code{#f} if @var{p} is composite; @code{#t} if @var{p} is -prime. There is a slight chance @code{(expt 2 (- prime:trials))} that a -composite will return @code{#t}.@refill +@defun for-each-row +Returns a procedure of arguments @var{proc} @var{match-key1} @dots{} +which calls @var{proc} with each @var{row} in this table in the +(implementation-dependent) natural ordering for rows. The optional +@var{match-key1} @dots{} arguments restrict actions to a subset of the +table. See the match-key description below for details. + +@emph{Real} relational programmers would use some least-upper-bound join +for every row to get them in order; But we don't have joins yet. @end defun -@defun prime:trials -Is the maxinum number of iterations of Solovay-Strassen that will be -done to test a number for primality. +@noindent +@cindex match-keys +The (optional) @var{match-key1} @dots{} arguments are used to restrict +actions of a whole-table operation to a subset of that table. Those +procedures (returned by methods) which accept match-key arguments will +accept any number of match-key arguments between zero and the number of +primary keys in the table. Any unspecified @var{match-key} arguments +default to @code{#f}. + +@noindent +The @var{match-key1} @dots{} restrict the actions of the table command +to those records whose primary keys each satisfy the corresponding +@var{match-key} argument. The arguments and their actions are: + +@quotation +@table @asis +@item @code{#f} +The false value matches any key in the corresponding position. +@item an object of type procedure +This procedure must take a single argument, the key in the corresponding +position. Any key for which the procedure returns a non-false value is +a match; Any key for which the procedure returns a @code{#f} is not. +@item other values +Any other value matches only those keys @code{equal?} to it. +@end table +@end quotation + +@defun close-table +Subsequent operations to this table will signal an error. @end defun +@defvr Constant column-names +@defvrx Constant column-foreigns +@defvrx Constant column-domains +@defvrx Constant column-types +Return a list of the column names, foreign-key table names, domain +names, or type names respectively for this table. These 4 methods are +different from the others in that the list is returned, rather than a +procedure to obtain the list. +@defvrx Constant primary-limit +Returns the number of primary keys fields in the relations in this +table. +@end defvr -@node Random Numbers, Cyclic Checksum, Prime Factorization, Numerics -@section Random Numbers +@node Catalog Representation, Unresolved Issues, Table Operations, Relational Database +@subsection Catalog Representation -@code{(require 'random)} +@noindent +Each database (in an implementation) has a @dfn{system catalog} which +describes all the user accessible tables in that database (including +itself). +@noindent +The system catalog base table has the following fields. @code{PRI} +indicates a primary key for that table. -@deffn Procedure random n -@deffnx Procedure random n state -Accepts a positive integer or real @var{n} and returns a number of the -same type between zero (inclusive) and @var{n} (exclusive). The values -returned have a uniform distribution.@refill +@example +@group +PRI table-name + column-limit the highest column number + coltab-name descriptor table name + bastab-id data base table identifier + user-integrity-rule + view-procedure A scheme thunk which, when called, + produces a handle for the view. coltab + and bastab are specified if and only if + view-procedure is not. +@end group +@end example -The optional argument @var{state} must be of the type produced by -@code{(make-random-state)}. It defaults to the value of the variable -@code{*random-state*}. This object is used to maintain the state of the -pseudo-random-number generator and is altered as a side effect of the -@code{random} operation.@refill -@end deffn +@noindent +Descriptors for base tables (not views) are tables (pointed to by +system catalog). Descriptor (base) tables have the fields: -@defvar *random-state* -Holds a data structure that encodes the internal state of the -random-number generator that @code{random} uses by default. The nature -of this data structure is implementation-dependent. It may be printed -out and successfully read back in, but may or may not function correctly -as a random-number state object in another implementation.@refill -@end defvar +@example +@group +PRI column-number sequential integers from 1 + primary-key? boolean TRUE for primary key components + column-name + column-integrity-rule + domain-name +@end group +@end example -@deffn Procedure make-random-state -@deffnx Procedure make-random-state state -Returns a new object of type suitable for use as the value of the -variable @code{*random-state*} and as a second argument to -@code{random}. If argument @var{state} is given, a copy of it is -returned. Otherwise a copy of @code{*random-state*} is returned.@refill -@end deffn +@noindent +A @dfn{primary key} is any column marked as @code{primary-key?} in the +corresponding descriptor table. All the @code{primary-key?} columns +must have lower column numbers than any non-@code{primary-key?} columns. +Every table must have at least one primary key. Primary keys must be +sufficient to distinguish all rows from each other in the table. All of +the system defined tables have a single primary key. -If inexact numbers are support by the Scheme implementation, -@file{randinex.scm} will be loaded as well. @file{randinex.scm} -contains procedures for generating inexact distributions.@refill +@noindent +This package currently supports tables having from 1 to 4 primary keys +if there are non-primary columns, and any (natural) number if @emph{all} +columns are primary keys. If you need more than 4 primary keys, I would +like to hear what you are doing! -@deffn Procedure random:uniform state -Returns an uniformly distributed inexact real random number in the -range between 0 and 1. -@end deffn +@noindent +A @dfn{domain} is a category describing the allowable values to occur in +a column. It is described by a (base) table with the fields: -@deffn Procedure random:solid-sphere! vect -@deffnx Procedure random:solid-sphere! vect state -Fills @var{vect} with inexact real random numbers the sum of whose -squares is less than 1.0. Thinking of @var{vect} as coordinates in -space of dimension @var{n} = @code{(vector-length @var{vect})}, the -coordinates are uniformly distributed within the unit @var{n}-shere. -The sum of the squares of the numbers is returned.@refill -@end deffn +@example +@group +PRI domain-name + foreign-table + domain-integrity-rule + type-id + type-param +@end group +@end example -@deffn Procedure random:hollow-sphere! vect -@deffnx Procedure random:hollow-sphere! vect state -Fills @var{vect} with inexact real random numbers the sum of whose -squares is equal to 1.0. Thinking of @var{vect} as coordinates in space -of dimension n = @code{(vector-length @var{vect})}, the coordinates are -uniformly distributed over the surface of the unit n-shere.@refill -@end deffn +@noindent +The @dfn{type-id} field value is a symbol. This symbol may be used by +the underlying base table implementation in storing that field. -@deffn Procedure random:normal -@deffnx Procedure random:normal state -Returns an inexact real in a normal distribution with mean 0 and -standard deviation 1. For a normal distribution with mean @var{m} and -standard deviation @var{d} use @code{(+ @var{m} (* @var{d} -(random:normal)))}.@refill -@end deffn +@noindent +If the @code{foreign-table} field is non-@code{#f} then that field names +a table from the catalog. The values for that domain must match a +primary key of the table referenced by the @var{type-param} (or +@code{#f}, if allowed). This package currently does not support +composite foreign-keys. -@deffn Procedure random:normal-vector! vect -@deffnx Procedure random:normal-vector! vect state -Fills @var{vect} with inexact real random numbers which are independent -and standard normally distributed (i.e., with mean 0 and variance 1). -@end deffn +@noindent +The types for which support is planned are: +@example +@group + atom + symbol + string [] + number [] + money + date-time + boolean -@deffn Procedure random:exp -@deffnx Procedure random:exp state -Returns an inexact real in an exponential distribution with mean 1. For -an exponential distribution with mean @var{u} use (* @var{u} -(random:exp)).@refill -@end deffn + foreign-key + expression + virtual +@end group +@end example + +@node Unresolved Issues, Database Utilities, Catalog Representation, Relational Database +@subsection Unresolved Issues + +Although @file{rdms.scm} is not large, I found it very difficult to +write (six rewrites). I am not aware of any other examples of a +generalized relational system (although there is little new in CS). I +left out several aspects of the Relational model in order to simplify +the job. The major features lacking (which might be addressed portably) +are views, transaction boundaries, and protection. + +Protection needs a model for specifying priveledges. Given how +operations are accessed from handles it should not be difficult to +restrict table accesses to those allowed for that user. + +The system catalog has a field called @code{view-procedure}. This +should allow a purely functional implementation of views. This will +work but is unsatisfying for views resulting from a @dfn{select}ion +(subset of rows); for whole table operations it will not be possible to +reduce the number of keys scanned over when the selection is specified +only by an opaque procedure. + +Transaction boundaries present the most intriguing area. Transaction +boundaries are actually a feature of the "Comprehensive Language" of the +Relational database and not of the database. Scheme would seem to +provide the opportunity for an extremely clean semantics for transaction +boundaries since the builtin procedures with side effects are small in +number and easily identified. + +These side-effect builtin procedures might all be portably redefined to +versions which properly handled transactions. Compiled library routines +would need to be recompiled as well. Many system extensions +(delete-file, system, etc.) would also need to be redefined. + +@noindent +There are 2 scope issues that must be resolved for multiprocess +transaction boundaries: + +@table @asis +@item Process scope +The actions captured by a transaction should be only for the process +which invoked the start of transaction. Although standard Scheme does +not provide process primitives as such, @code{dynamic-wind} would +provide a workable hook into process switching for many implementations. +@item Shared utilities with state +Some shared utilities have state which should @emph{not} be part of a +transaction. An example would be calling a pseudo-random number +generator. If the success of a transaction depended on the +pseudo-random number and failed, the state of the generator would be set +back. Subsequent calls would keep returning the same number and keep +failing. + +Pseudo-random number generators are not reentrant; thus they would +require locks in order to operate properly in a multiprocess +environment. Are all examples of utilities whose state should not be +part of transactions also non-reentrant? If so, perhaps suspending +transaction capture for the duration of locks would solve this problem. +@end table +@node Database Utilities, , Unresolved Issues, Relational Database +@subsection Database Utilities -@node Cyclic Checksum, Plotting, Random Numbers, Numerics -@section Cyclic Checksum +@code{(require 'database-utilities)} +@ftindex database-utilities -@code{(require 'make-crc)} +@noindent +This enhancement wraps a utility layer on @code{relational-database} +which provides: +@itemize @bullet +@item +Automatic loading of the appropriate base-table package when opening a +database. +@item +Automatic execution of initialization commands stored in database. +@item +Transparent execution of database commands stored in @code{*commands*} +table in database. +@end itemize -@defun make-port-crc -@defunx make-port-crc degree -@defunx make-port-crc degree generator -Returns an expression for a procedure of one argument, a port. This -procedure reads characters from the port until the end of file and -returns the integer checksum of the bytes read. +@noindent +Also included are utilities which provide: +@itemize @bullet +@item +Data definition from Scheme lists and +@item +Report generation +@end itemize +@noindent +for any SLIB relational database. -The integer @var{degree}, if given, specifies the degree of the -polynomial being computed -- which is also the number of bits computed -in the checksums. The default value is 32. +@defun create-database filename base-table-type +Returns an open, nearly empty enhanced (with @code{*commands*} table) +relational database (with base-table type @var{base-table-type}) +associated with @var{filename}. +@end defun -The integer @var{generator} specifies the polynomial being computed. -The power of 2 generating each 1 bit is the exponent of a term of the -polynomial. The bit at position @var{degree} is implicit and should not -be part of @var{generator}. This allows systems with numbers limited to -32 bits to calculate 32 bit checksums. The default value of -@var{generator} when @var{degree} is 32 (its default) is: +@defun open-database filename +@defunx open-database filename base-table-type +Returns an open enchanced relational database associated with +@var{filename}. The database will be opened with base-table type +@var{base-table-type}) if supplied. If @var{base-table-type} is not +supplied, @code{open-database} will attempt to deduce the correct +base-table-type. If the database can not be opened or if it lacks the +@code{*commands*} table, @code{#f} is returned. +@defunx open-database! filename +@defunx open-database! filename base-table-type +Returns @emph{mutable} open enchanced relational database @dots{} +@end defun + +@noindent +The table @code{*commands*} in an @dfn{enhanced} relational-database has +the fields (with domains): @example -(make-port-crc 32 #b00000100110000010001110110110111) +@group +PRI name symbol + parameters parameter-list + procedure expression + documentation string +@end group @end example -Creates a procedure to calculate the P1003.2/D11.2 (POSIX.2) 32-bit -checksum from the polynomial: - +The @code{parameters} field is a foreign key (domain +@code{parameter-list}) of the @code{*catalog-data*} table and should +have the value of a table described by @code{*parameter-columns*}. This +@code{parameter-list} table describes the arguments suitable for passing +to the associated command. The intent of this table is to be of a form +such that different user-interfaces (for instance, pull-down menus or +plain-text queries) can operate from the same table. A +@code{parameter-list} table has the following fields: @example - 32 26 23 22 16 12 11 - ( x + x + x + x + x + x + x + - - 10 8 7 5 4 2 1 - x + x + x + x + x + x + x + 1 ) mod 2 +@group +PRI index uint + name symbol + arity parameter-arity + domain domain + defaulter expression + expander expression + documentation string +@end group @end example -@end defun -@example -(require 'make-crc) -(define crc32 (slib:eval (make-port-crc))) -(define (file-check-sum file) (call-with-input-file file crc32)) -(file-check-sum (in-vicinity (library-vicinity) "ratize.scm")) +The @code{arity} field can take the values: -@result{} 3553047446 -@end example +@table @code +@item single +Requires a single parameter of the specified domain. +@item optional +A single parameter of the specified domain or zero parameters is +acceptable. +@item boolean +A single boolean parameter or zero parameters (in which case @code{#f} +is substituted) is acceptable. +@item nary +Any number of parameters of the specified domain are acceptable. The +argument passed to the command function is always a list of the +parameters. +@item nary1 +One or more of parameters of the specified domain are acceptable. The +argument passed to the command function is always a list of the +parameters. +@end table -@node Plotting, Root Finding, Cyclic Checksum, Numerics -@section Plotting on Character Devices +The @code{domain} field specifies the domain which a parameter or +parameters in the @code{index}th field must satisfy. -@code{(require 'charplot)} +The @code{defaulter} field is an expression whose value is either +@code{#f} or a procedure of one argument (the parameter-list) which +returns a @emph{list} of the default value or values as appropriate. +Note that since the @code{defaulter} procedure is called every time a +default parameter is needed for this column, @dfn{sticky} defaults can +be implemented using shared state with the domain-integrity-rule. -The plotting procedure is made available through the use of the -@code{charplot} package. @code{charplot} is loaded by inserting -@code{(require 'charplot)} before the code that uses this -procedure.@refill +@subsubheading Invoking Commands -@defvar charplot:height -The number of rows to make the plot vertically. -@end defvar +When an enhanced relational-database is called with a symbol which +matches a @var{name} in the @code{*commands*} table, the associated +procedure expression is evaluated and applied to the enhanced +relational-database. A procedure should then be returned which the user +can invoke on (optional) arguments. -@defvar charplot:width -The number of columns to make the plot horizontally. -@end defvar +The command @code{*initialize*} is special. If present in the +@code{*commands*} table, @code{open-database} or @code{open-database!} +will return the value of the @code{*initialize*} command. Notice that +arbitrary code can be run when the @code{*initialize*} procedure is +automatically applied to the enhanced relational-database. -@deffn Procedure plot! coords x-label y-label -@var{coords} is a list of pairs of x and y coordinates. @var{x-label} -and @var{y-label} are strings with which to label the x and y -axes.@refill +Note also that if you wish to shadow or hide from the user +relational-database methods described in @ref{Relational Database +Operations}, this can be done by a dispatch in the closure returned by +the @code{*initialize*} expression rather than by entries in the +@code{*commands*} table if it is desired that the underlying methods +remain accessible to code in the @code{*commands*} table. + +@defun make-command-server rdb table-name +Returns a procedure of 2 arguments, a (symbol) command and a call-back +procedure. When this returned procedure is called, it looks up +@var{command} in table @var{table-name} and calls the call-back +procedure with arguments: +@table @var +@item command +The @var{command} +@item command-value +The result of evaluating the expression in the @var{procedure} field of +@var{table-name} and calling it with @var{rdb}. +@item parameter-name +A list of the @dfn{official} name of each parameter. Corresponds to the +@code{name} field of the @var{command}'s parameter-table. +@item positions +A list of the positive integer index of each parameter. Corresponds to +the @code{index} field of the @var{command}'s parameter-table. +@item arities +A list of the arities of each parameter. Corresponds to the +@code{arity} field of the @var{command}'s parameter-table. For a +description of @code{arity} see table above. +@item types +A list of the type name of each parameter. Correspnds to the +@code{type-id} field of the contents of the @code{domain} of the +@var{command}'s parameter-table. +@item defaulters +A list of the defaulters for each parameter. Corresponds to +the @code{defaulters} field of the @var{command}'s parameter-table. +@item domain-integrity-rules +A list of procedures (one for each parameter) which tests whether a +value for a parameter is acceptable for that parameter. The procedure +should be called with each datum in the list for @code{nary} arity +parameters. +@item aliases +A list of lists of @code{(@r{alias} @r{parameter-name})}. There can be +more than one alias per @var{parameter-name}. +@end table +@end defun + +For information about parameters, @xref{Parameter lists}. Here is an +example of setting up a command with arguments and parsing those +arguments from a @code{getopt} style argument list (@pxref{Getopt}). -Example: @example -(require 'charplot) -(set! charplot:height 19) -(set! charplot:width 45) +(require 'database-utilities) +@ftindex database-utilities +(require 'fluid-let) +@ftindex fluid-let +(require 'parameters) +@ftindex parameters +(require 'getopt) +@ftindex getopt -(define (make-points n) - (if (zero? n) - '() - (cons (cons (/ n 6) (sin (/ n 6))) (make-points (1- n))))) +(define my-rdb (create-database #f 'alist-table)) -(plot! (make-points 37) "x" "Sin(x)") -@print{} -@group - Sin(x) ______________________________________________ - 1.25|- | - | | - 1|- **** | - | ** ** | - 750.0e-3|- * * | - | * * | - 500.0e-3|- * * | - | * | - 250.0e-3|- * | - | * * | - 0|-------------------*--------------------------| - | * | - -250.0e-3|- * * | - | * * | - -500.0e-3|- * | - | * * | - -750.0e-3|- * * | - | ** ** | - -1|- **** | - |____________:_____._____:_____._____:_________| - x 2 4 -@end group -@end example -@end deffn +(define-tables my-rdb + '(foo-params + *parameter-columns* + *parameter-columns* + ((1 single-string single string + (lambda (pl) '("str")) #f "single string") + (2 nary-symbols nary symbol + (lambda (pl) '()) #f "zero or more symbols") + (3 nary1-symbols nary1 symbol + (lambda (pl) '(symb)) #f "one or more symbols") + (4 optional-number optional uint + (lambda (pl) '()) #f "zero or one number") + (5 flag boolean boolean + (lambda (pl) '(#f)) #f "a boolean flag"))) + '(foo-pnames + ((name string)) + ((parameter-index uint)) + (("s" 1) + ("single-string" 1) + ("n" 2) + ("nary-symbols" 2) + ("N" 3) + ("nary1-symbols" 3) + ("o" 4) + ("optional-number" 4) + ("f" 5) + ("flag" 5))) + '(my-commands + ((name symbol)) + ((parameters parameter-list) + (parameter-names parameter-name-translation) + (procedure expression) + (documentation string)) + ((foo + foo-params + foo-pnames + (lambda (rdb) (lambda args (print args))) + "test command arguments")))) +(define (dbutil:serve-command-line rdb command-table + command argc argv) + (set! argv (if (vector? argv) (vector->list argv) argv)) + ((make-command-server rdb command-table) + command + (lambda (comname comval options positions + arities types defaulters dirs aliases) + (apply comval (getopt->arglist + argc argv options positions + arities types defaulters dirs aliases))))) + +(define (cmd . opts) + (fluid-let ((*optind* 1)) + (printf "%-34s @result{} " + (call-with-output-string (lambda (pt) (write (cons 'cmd opts) pt))) + ;;(apply string-append (map (lambda (x) (string-append x " ")) opts)) + ) + (set! opts (cons "cmd" opts)) + (force-output) + (dbutil:serve-command-line + my-rdb 'my-commands 'foo (length opts) opts))) + +(cmd) @result{} ("str" () (symb) () #f) +(cmd "-f") @result{} ("str" () (symb) () #t) +(cmd "--flag") @result{} ("str" () (symb) () #t) +(cmd "-o177") @result{} ("str" () (symb) (177) #f) +(cmd "-o" "177") @result{} ("str" () (symb) (177) #f) +(cmd "--optional" "621") @result{} ("str" () (symb) (621) #f) +(cmd "--optional=621") @result{} ("str" () (symb) (621) #f) +(cmd "-s" "speciality") @result{} ("speciality" () (symb) () #f) +(cmd "-sspeciality") @result{} ("speciality" () (symb) () #f) +(cmd "--single" "serendipity") @result{} ("serendipity" () (symb) () #f) +(cmd "--single=serendipity") @result{} ("serendipity" () (symb) () #f) +(cmd "-n" "gravity" "piety") @result{} ("str" () (piety gravity) () #f) +(cmd "-ngravity" "piety") @result{} ("str" () (piety gravity) () #f) +(cmd "--nary" "chastity") @result{} ("str" () (chastity) () #f) +(cmd "--nary=chastity" "") @result{} ("str" () ( chastity) () #f) +(cmd "-N" "calamity") @result{} ("str" () (calamity) () #f) +(cmd "-Ncalamity") @result{} ("str" () (calamity) () #f) +(cmd "--nary1" "surety") @result{} ("str" () (surety) () #f) +(cmd "--nary1=surety") @result{} ("str" () (surety) () #f) +(cmd "-N" "levity" "fealty") @result{} ("str" () (fealty levity) () #f) +(cmd "-Nlevity" "fealty") @result{} ("str" () (fealty levity) () #f) +(cmd "--nary1" "surety" "brevity") @result{} ("str" () (brevity surety) () #f) +(cmd "--nary1=surety" "brevity") @result{} ("str" () (brevity surety) () #f) +(cmd "-?") +@print{} +Usage: cmd [OPTION ARGUMENT ...] ... + + -f, --flag + -o, --optional[=] + -n, --nary[=] ... + -N, --nary1[=] ... + -s, --single[=] + +ERROR: getopt->parameter-list "unrecognized option" "-?" +@end example -@node Root Finding, , Plotting, Numerics -@section Root Finding +Some commands are defined in all extended relational-databases. The are +called just like @ref{Relational Database Operations}. -@code{(require 'root)} +@defun add-domain domain-row +Adds @var{domain-row} to the @dfn{domains} table if there is no row in +the domains table associated with key @code{(car @var{domain-row})} and +returns @code{#t}. Otherwise returns @code{#f}. -@defun newtown:find-integer-root f df/dx x0 -Given integer valued procedure @var{f}, its derivative (with respect to -its argument) @var{df/dx}, and initial integer value @var{x0} for which -@var{df/dx}(@var{x0}) is non-zero, returns an integer @var{x} for which -@var{f}(@var{x}) is closer to zero than either of the integers adjacent -to @var{x}; or returns @code{#f} if such an integer can't be found. +For the fields and layout of the domain table, @xref{Catalog +Representation}. Currently, these fields are +@itemize @bullet +@item +domain-name +@item +foreign-table +@item +domain-integrity-rule +@item +type-id +@item +type-param +@end itemize -To find the closest integer to a given integers square root: +The following example adds 3 domains to the @samp{build} database. +@samp{Optstring} is either a string or @code{#f}. @code{filename} is a +string and @code{build-whats} is a symbol. @example -(define (integer-sqrt y) - (newton:find-integer-root - (lambda (x) (- (* x x) y)) - (lambda (x) (* 2 x)) - (ash 1 (quotient (integer-length y) 2)))) - -(integer-sqrt 15) @result{} 4 +(for-each (build 'add-domain) + '((optstring #f + (lambda (x) (or (not x) (string? x))) + string + #f) + (filename #f #f string #f) + (build-whats #f #f symbol #f))) @end example @end defun -@defun integer-sqrt y -Given a non-negative integer @var{y}, returns the rounded square-root of -@var{y}. +@defun delete-domain domain-name +Removes and returns the @var{domain-name} row from the @dfn{domains} +table. @end defun -@defun newton:find-root f df/dx x0 prec -Given real valued procedures @var{f}, @var{df/dx} of one (real) -argument, initial real value @var{x0} for which @var{df/dx}(@var{x0}) is -non-zero, and positive real number @var{prec}, returns a real @var{x} -for which @code{abs}(@var{f}(@var{x})) is less than @var{prec}; or -returns @code{#f} if such a real can't be found. - -If @code{prec} is instead a negative integer, @code{newton:find-root} -returns the result of -@var{prec} iterations. +@defun domain-checker domain +Returns a procedure to check an argument for conformance to domain +@var{domain}. @end defun -@noindent -H. J. Orchard, @cite{The Laguerre Method for Finding the Zeros of -Polynomials}, IEEE Transactions on Circuits and Systems, Vol. 36, -No. 11, November 1989, pp 1377-1381. +@subsubheading Defining Tables -@quotation -There are 2 errors in Orchard's Table II. Line k=2 for starting -value of 1000+j0 should have Z_k of 1.0475 + j4.1036 and line k=2 -for starting value of 0+j1000 should have Z_k of 1.0988 + j4.0833. -@end quotation +@deffn Procedure define-tables rdb spec-0 @dots{} +Adds tables as specified in @var{spec-0} @dots{} to the open +relational-database @var{rdb}. Each @var{spec} has the form: +@lisp +(@r{} @r{} @r{} @r{}) +@end lisp +or +@lisp +(@r{} @r{} @r{} @r{}) +@end lisp -@defun laguerre:find-root f df/dz ddf/dz^2 z0 prec -Given complex valued procedure @var{f} of one (complex) argument, its -derivative (with respect to its argument) @var{df/dx}, its second -derivative @var{ddf/dz^2}, initial complex value @var{z0}, and positive -real number @var{prec}, returns a complex number @var{z} for which -@code{magnitude}(@var{f}(@var{z})) is less than @var{prec}; or returns -@code{#f} if such a number can't be found. +where @r{} is the table name, @r{} is the symbol +name of a descriptor table, @r{} and +@r{} describe the primary keys and other fields +respectively, and @r{} is a list of data rows to be added to the +table. -If @code{prec} is instead a negative integer, @code{laguerre:find-root} -returns the result of -@var{prec} iterations. -@end defun +@r{} and @r{} are lists of field +descriptors of the form: -@defun laguerre:find-polynomial-root deg f df/dz ddf/dz^2 z0 prec -Given polynomial procedure @var{f} of integer degree @var{deg} of one -argument, its derivative (with respect to its argument) @var{df/dx}, its -second derivative @var{ddf/dz^2}, initial complex value @var{z0}, and -positive real number @var{prec}, returns a complex number @var{z} for -which @code{magnitude}(@var{f}(@var{z})) is less than @var{prec}; or -returns @code{#f} if such a number can't be found. +@lisp +(@r{} @r{}) +@end lisp +or +@lisp +(@r{} @r{} @r{}) +@end lisp -If @code{prec} is instead a negative integer, -@code{laguerre:find-polynomial-root} returns the result of -@var{prec} -iterations. -@end defun +where @r{} is the column name, @r{} is the domain +of the column, and @r{} is an expression whose +value is a procedure of one argument (which returns @code{#f} to signal +an error). +If @r{} is not a defined domain name and it matches the name of +this table or an already defined (in one of @var{spec-0} @dots{}) single +key field table, a foriegn-key domain will be created for it. +@end deffn -@node Procedures, Standards Support, Numerics, Top -@chapter Procedures -Anything that doesn't fall neatly into any of the other categories winds -up here. +@deffn Procedure create-report rdb destination report-name table +@deffnx Procedure create-report rdb destination report-name +The symbol @var{report-name} must be primary key in the table named +@code{*reports*} in the relational database @var{rdb}. +@var{destination} is a port, string, or symbol. If @var{destination} is +a: -@menu -* Batch:: 'batch -* Common List Functions:: 'common-list-functions -* Format:: 'format -* Generic-Write:: 'generic-write -* Line I/O:: 'line-i/o -* Multi-Processing:: 'process -* Object-To-String:: 'object->string -* Pretty-Print:: 'pretty-print, 'pprint-file -* Sorting:: 'sort -* Topological Sort:: -* Standard Formatted I/O:: 'printf, 'scanf -* String-Case:: 'string-case -* String Ports:: 'string-port -* String Search:: -* Tektronix Graphics Support:: -* Tree Operations:: 'tree -@end menu +@table @asis +@item port +The table is created as ascii text and written to that port. +@item string +The table is created as ascii text and written to the file named by +@var{destination}. +@item symbol +@var{destination} is the primary key for a row in the table named *printers*. +@end table + +Each row in the table *reports* has the fields: + +@table @asis +@item name +The report name. +@item default-table +The table to report on if none is specified. +@item header, footer +A @code{format} string. At the beginning and end of each page +respectively, @code{format} is called with this string and the (list of) +column-names of this table. +@item reporter +A @code{format} string. For each row in the table, @code{format} is +called with this string and the row. +@item minimum-break +The minimum number of lines into which the report lines for a row can be +broken. Use @code{0} if a row's lines should not be broken over page +boundaries. +@end table + +Each row in the table *printers* has the fields: + +@table @asis +@item name +The printer name. +@item print-procedure +The procedure to call to actually print. +@end table + +The report is prepared as follows: + +@itemize @bullet +@item +@code{Format} (@pxref{Format}) is called with the @code{header} field +and the (list of) @code{column-names} of the table. +@item +@code{Format} is called with the @code{reporter} field and (on +successive calls) each record in the natural order for the table. A +count is kept of the number of newlines output by format. When the +number of newlines to be output exceeds the number of lines per page, +the set of lines will be broken if there are more than +@code{minimum-break} left on this page and the number of lines for this +row is larger or equal to twice @code{minimum-break}. +@item +@code{Format} is called with the @code{footer} field and the (list of) +@code{column-names} of the table. The footer field should not output a +newline. +@item +A new page is output. +@item +This entire process repeats until all the rows are output. +@end itemize +@end deffn + +@noindent +The following example shows a new database with the name of +@file{foo.db} being created with tables describing processor families +and processor/os/compiler combinations. + +@noindent +The database command @code{define-tables} is defined to call +@code{define-tables} with its arguments. The database is also +configured to print @samp{Welcome} when the database is opened. The +database is then closed and reopened. + +@example +(require 'database-utilities) +@ftindex database-utilities +(define my-rdb (create-database "foo.db" 'alist-table)) + +(define-tables my-rdb + '(*commands* + ((name symbol)) + ((parameters parameter-list) + (procedure expression) + (documentation string)) + ((define-tables + no-parameters + no-parameter-names + (lambda (rdb) (lambda specs (apply define-tables rdb specs))) + "Create or Augment tables from list of specs") + (*initialize* + no-parameters + no-parameter-names + (lambda (rdb) (display "Welcome") (newline) rdb) + "Print Welcome")))) + +((my-rdb 'define-tables) + '(processor-family + ((family atom)) + ((also-ran processor-family)) + ((m68000 #f) + (m68030 m68000) + (i386 8086) + (8086 #f) + (powerpc #f))) + + '(platform + ((name symbol)) + ((processor processor-family) + (os symbol) + (compiler symbol)) + ((aix powerpc aix -) + (amiga-dice-c m68000 amiga dice-c) + (amiga-aztec m68000 amiga aztec) + (amiga-sas/c-5.10 m68000 amiga sas/c) + (atari-st-gcc m68000 atari gcc) + (atari-st-turbo-c m68000 atari turbo-c) + (borland-c-3.1 8086 ms-dos borland-c) + (djgpp i386 ms-dos gcc) + (linux i386 linux gcc) + (microsoft-c 8086 ms-dos microsoft-c) + (os/2-emx i386 os/2 gcc) + (turbo-c-2 8086 ms-dos turbo-c) + (watcom-9.0 i386 ms-dos watcom)))) + +((my-rdb 'close-database)) -@node Batch, Common List Functions, Procedures, Procedures -@section Batch +(set! my-rdb (open-database "foo.db" 'alist-table)) +@print{} +Welcome +@end example -@code{(require 'batch)} -@noindent -The batch procedures provide a way to write and execute portable scripts -for a variety of operating systems. Each @code{batch:} procedure takes -as its first argument a parameter-list (@pxref{Parameter lists}). This -parameter-list argument @var{parms} contains named associations. Batch -currently uses 2 of these: +@node Weight-Balanced Trees, , Relational Database, Database Packages +@section Weight-Balanced Trees + +@code{(require 'wt-tree)} +@ftindex wt-tree + +@cindex trees, balanced binary +@cindex balanced binary trees +@cindex binary trees +@cindex weight-balanced binary trees +Balanced binary trees are a useful data structure for maintaining large +sets of ordered objects or sets of associations whose keys are ordered. +MIT Scheme has an comprehensive implementation of weight-balanced binary +trees which has several advantages over the other data structures for +large aggregates: -@table @code -@item batch-port -The port on which to write lines of the batch file. -@item batch-dialect -The syntax of batch file to generate. Currently supported are: @itemize @bullet @item -unix -@item -dos +In addition to the usual element-level operations like insertion, +deletion and lookup, there is a full complement of collection-level +operations, like set intersection, set union and subset test, all of +which are implemented with good orders of growth in time and space. +This makes weight balanced trees ideal for rapid prototyping of +functionally derived specifications. + @item -vms +An element in a tree may be indexed by its position under the ordering +of the keys, and the ordinal position of an element may be determined, +both with reasonable efficiency. + @item -system +Operations to find and remove minimum element make weight balanced trees +simple to use for priority queues. + @item -*unknown* +The implementation is @emph{functional} rather than @emph{imperative}. +This means that operations like `inserting' an association in a tree do +not destroy the old tree, in much the same way that @code{(+ 1 x)} +modifies neither the constant 1 nor the value bound to @code{x}. The +trees are referentially transparent thus the programmer need not worry +about copying the trees. Referential transparency allows space +efficiency to be achieved by sharing subtrees. + @end itemize -@end table -@noindent -@file{batch.scm} uses 2 enhanced relational tables (@pxref{Database -Utilities}) to store information linking the names of -@code{operating-system}s to @code{batch-dialect}es. +These features make weight-balanced trees suitable for a wide range of +applications, especially those that +require large numbers of sets or discrete maps. Applications that have +a few global databases and/or concentrate on element-level operations like +insertion and lookup are probably better off using hash-tables or +red-black trees. -@defun batch:initialize! database -Defines @code{operating-system} and @code{batch-dialect} tables and adds -the domain @code{operating-system} to the enhanced relational database -@var{database}. -@end defun +The @emph{size} of a tree is the number of associations that it +contains. Weight balanced binary trees are balanced to keep the sizes +of the subtrees of each node within a constant factor of each other. +This ensures logarithmic times for single-path operations (like lookup +and insertion). A weight balanced tree takes space that is proportional +to the number of associations in the tree. For the current +implementation, the constant of proportionality is six words per +association. -@defvar batch:platform -Is batch's best guess as to which operating-system it is running under. -@code{batch:platform} is set to @code{(software-type)} -(@pxref{Configuration}) unless @code{(software-type)} is @code{unix}, -in which case finer distinctions are made. -@end defvar +@cindex binary trees, as sets +@cindex binary trees, as discrete maps +@cindex sets, using binary trees +@cindex discrete maps, using binary trees +Weight balanced trees can be used as an implementation for either +discrete sets or discrete maps (associations). Sets are implemented by +ignoring the datum that is associated with the key. Under this scheme +if an associations exists in the tree this indicates that the key of the +association is a member of the set. Typically a value such as +@code{()}, @code{#t} or @code{#f} is associated with the key. -@defun batch:call-with-output-script parms file proc -@var{proc} should be a procedure of one argument. If @var{file} is an -output-port, @code{batch:call-with-output-script} writes an appropriate -header to @var{file} and then calls @var{proc} with @var{file} as the -only argument. If @var{file} is a string, -@code{batch:call-with-output-script} opens a output-file of name -@var{file}, writes an appropriate header to @var{file}, and then calls -@var{proc} with the newly opened port as the only argument. Otherwise, -@code{batch:call-with-output-script} acts as if it was called with the -result of @code{(current-output-port)} as its third argument. -@end defun +Many operations can be viewed as computing a result that, depending on +whether the tree arguments are thought of as sets or maps, is known by +two different names. +An example is @code{wt-tree/member?}, which, when +regarding the tree argument as a set, computes the set membership operation, but, +when regarding the tree as a discrete map, @code{wt-tree/member?} is the +predicate testing if the map is defined at an element in its domain. +Most names in this package have been chosen based on interpreting the +trees as sets, hence the name @code{wt-tree/member?} rather than +@code{wt-tree/defined-at?}. -@defun batch:apply-chop-to-fit proc arg1 arg2 @dots{} list -The procedure @var{proc} must accept at least one argument and return -@code{#t} if successful, @code{#f} if not. -@code{batch:apply-chop-to-fit} calls @var{proc} with @var{arg1}, -@var{arg2}, @dots{}, and @var{chunk}, where @var{chunk} is a subset of -@var{list}. @code{batch:apply-chop-to-fit} tries @var{proc} with -successively smaller subsets of @var{list} until either @var{proc} -returns non-false, or the @var{chunk}s become empty. -@end defun -@noindent -The rest of the @code{batch:} procedures write (or execute if -@code{batch-dialect} is @code{system}) commands to the batch port which -has been added to @var{parms} or @code{(copy-tree @var{parms})} by the -code: +@cindex run-time-loadable option +@cindex option, run-time-loadable +The weight balanced tree implementation is a run-time-loadable option. +To use weight balanced trees, execute @example -(adjoin-parameters! @var{parms} (list 'batch-port @var{port})) +(load-option 'wt-tree) @end example - -@defun batch:system parms string1 string2 @dots{} -Calls @code{batch:try-system} (below) with arguments, but signals an -error if @code{batch:try-system} returns @code{#f}. -@end defun +@findex load-option @noindent -These functions return a non-false value if the command was successfully -translated into the batch dialect and @code{#f} if not. In the case of -the @code{system} dialect, the value is non-false if the operation -suceeded. - -@defun batch:try-system parms string1 string2 @dots{} -Writes a command to the @code{batch-port} in @var{parms} which executes -the program named @var{string1} with arguments @var{string2} @dots{}. -@end defun +once before calling any of the procedures defined here. -@defun batch:run-script parms string1 string2 @dots{} -Writes a command to the @code{batch-port} in @var{parms} which executes -the batch script named @var{string1} with arguments @var{string2} -@dots{}. -@emph{Note:} @code{batch:run-script} and @code{batch:try-system} are not the -same for some operating systems (VMS). -@end defun +@menu +* Construction of Weight-Balanced Trees:: +* Basic Operations on Weight-Balanced Trees:: +* Advanced Operations on Weight-Balanced Trees:: +* Indexing Operations on Weight-Balanced Trees:: +@end menu -@defun batch:comment parms line1 @dots{} -Writes comment lines @var{line1} @dots{} to the @code{batch-port} in -@var{parms}. -@end defun +@node Construction of Weight-Balanced Trees, Basic Operations on Weight-Balanced Trees, Weight-Balanced Trees, Weight-Balanced Trees +@subsection Construction of Weight-Balanced Trees -@defun batch:lines->file parms file line1 @dots{} -Writes commands to the @code{batch-port} in @var{parms} which create a -file named @var{file} with contents @var{line1} @dots{}. -@end defun +Binary trees require there to be a total order on the keys used to +arrange the elements in the tree. Weight balanced trees are organized +by @emph{types}, where the type is an object encapsulating the ordering +relation. Creating a tree is a two-stage process. First a tree type +must be created from the predicate which gives the ordering. The tree type +is then used for making trees, either empty or singleton trees or trees +from other aggregate structures like association lists. Once created, a +tree `knows' its type and the type is used to test compatibility between +trees in operations taking two trees. Usually a small number of tree +types are created at the beginning of a program and used many times +throughout the program's execution. -@defun batch:delete-file parms file -Writes a command to the @code{batch-port} in @var{parms} which deletes -the file named @var{file}. -@end defun +@deffn {procedure+} make-wt-tree-type keybatch-dialect osname -Returns its best guess for the @code{batch-dialect} to be used for the -operating-system named @var{osname}. @code{os->batch-dialect} uses the -tables added to @var{database} by @code{batch:initialize!}. -@end defun +@example +(define number-wt-type (make-wt-tree-type <)) +@end example +@end defvr -@noindent -Here is an example of the use of most of batch's procedures: +@defvr {variable+} string-wt-type +A standard tree type for trees with string keys. @code{String-wt-type} +could have been defined by @example -(require 'database-utilities) -(require 'parameters) -(require 'batch) +(define string-wt-type (make-wt-tree-type stringbatch-dialect batch:platform)) - (list 'platform batch:platform) - (list 'batch-port (current-output-port)))) ;gets filled in later -(batch:call-with-output-script - my-parameters - "my-batch" - (lambda (batch-port) - (adjoin-parameters! my-parameters (list 'batch-port batch-port)) - (and - (batch:comment my-parameters - "================ Write file with C program.") - (batch:rename-file my-parameters "hello.c" "hello.c~") - (batch:lines->file my-parameters "hello.c" - "#include " - "int main(int argc, char **argv)" - "@{" - " printf(\"hello world\\n\");" - " return 0;" - "@}" ) - (batch:system my-parameters "cc" "-c" "hello.c") - (batch:system my-parameters "cc" "-o" "hello" - (replace-suffix "hello.c" ".c" ".o")) - (batch:system my-parameters "hello") - (batch:delete-file my-parameters "hello") - (batch:delete-file my-parameters "hello.c") - (batch:delete-file my-parameters "hello.o") - (batch:delete-file my-parameters "my-batch") - ))) -@end example +@deffn {procedure+} make-wt-tree wt-tree-type +This procedure creates and returns a newly allocated weight balanced +tree. The tree is empty, i.e. it contains no associations. +@var{Wt-tree-type} is a weight balanced tree type obtained by calling +@code{make-wt-tree-type}; the returned tree has this type. +@end deffn -@noindent -Produces the file @file{my-batch}: +@deffn {procedure+} singleton-wt-tree wt-tree-type key datum +This procedure creates and returns a newly allocated weight balanced +tree. The tree contains a single association, that of @var{datum} with +@var{key}. @var{Wt-tree-type} is a weight balanced tree type obtained +by calling @code{make-wt-tree-type}; the returned tree has this type. +@end deffn + +@deffn {procedure+} alist->wt-tree tree-type alist +Returns a newly allocated weight-balanced tree that contains the same +associations as @var{alist}. This procedure is equivalent to: @example -#!/bin/sh -# "my-batch" build script created Sat Jun 10 21:20:37 1995 -# ================ Write file with C program. -mv -f hello.c hello.c~ -rm -f hello.c -echo '#include '>>hello.c -echo 'int main(int argc, char **argv)'>>hello.c -echo '@{'>>hello.c -echo ' printf("hello world\n");'>>hello.c -echo ' return 0;'>>hello.c -echo '@}'>>hello.c -cc -c hello.c -cc -o hello hello.o -hello -rm -f hello -rm -f hello.c -rm -f hello.o -rm -f my-batch +(lambda (type alist) + (let ((tree (make-wt-tree type))) + (for-each (lambda (association) + (wt-tree/add! tree + (car association) + (cdr association))) + alist) + tree)) @end example +@end deffn -@noindent -When run, @file{my-batch} prints: -@example -bash$ my-batch -mv: hello.c: No such file or directory -hello world -@end example +@node Basic Operations on Weight-Balanced Trees, Advanced Operations on Weight-Balanced Trees, Construction of Weight-Balanced Trees, Weight-Balanced Trees +@subsection Basic Operations on Weight-Balanced Trees -@node Common List Functions, Format, Batch, Procedures -@section Common List Functions +This section describes the basic tree operations on weight balanced +trees. These operations are the usual tree operations for insertion, +deletion and lookup, some predicates and a procedure for determining the +number of associations in a tree. -@code{(require 'common-list-functions)} +@deffn {procedure+} wt-tree? object +Returns @code{#t} if @var{object} is a weight-balanced tree, otherwise +returns @code{#f}. +@end deffn -The procedures below follow the Common LISP equivalents apart from -optional arguments in some cases. +@deffn {procedure+} wt-tree/empty? wt-tree +Returns @code{#t} if @var{wt-tree} contains no associations, otherwise +returns @code{#f}. +@end deffn -@menu -* List construction:: -* Lists as sets:: -* Lists as sequences:: -* Destructive list operations:: -* Non-List functions:: -@end menu +@deffn {procedure+} wt-tree/size wt-tree +Returns the number of associations in @var{wt-tree}, an exact +non-negative integer. This operation takes constant time. +@end deffn -@node List construction, Lists as sets, Common List Functions, Common List Functions -@subsection List construction +@deffn {procedure+} wt-tree/add wt-tree key datum +Returns a new tree containing all the associations in @var{wt-tree} and +the association of @var{datum} with @var{key}. If @var{wt-tree} already +had an association for @var{key}, the new association overrides the old. +The average and worst-case times required by this operation are +proportional to the logarithm of the number of associations in +@var{wt-tree}. +@end deffn -@defun make-list k . init -@code{make-list} creates and returns a list of @var{k} elements. If -@var{init} is included, all elements in the list are initialized to -@var{init}.@refill +@deffn {procedure+} wt-tree/add! wt-tree key datum +Associates @var{datum} with @var{key} in @var{wt-tree} and returns an +unspecified value. If @var{wt-tree} already has an association for +@var{key}, that association is replaced. The average and worst-case +times required by this operation are proportional to the logarithm of +the number of associations in @var{wt-tree}. +@end deffn -Example: -@lisp -(make-list 3) - @result{} (# # #) -(make-list 5 'foo) - @result{} (foo foo foo foo foo) -@end lisp -@end defun +@deffn {procedure+} wt-tree/member? key wt-tree +Returns @code{#t} if @var{wt-tree} contains an association for +@var{key}, otherwise returns @code{#f}. The average and worst-case +times required by this operation are proportional to the logarithm of +the number of associations in @var{wt-tree}. +@end deffn +@deffn {procedure+} wt-tree/lookup wt-tree key default +Returns the datum associated with @var{key} in @var{wt-tree}. If +@var{wt-tree} doesn't contain an association for @var{key}, +@var{default} is returned. The average and worst-case times required by +this operation are proportional to the logarithm of the number of +associations in @var{wt-tree}. +@end deffn -@defun list* x . y -Works like @code{list} except that the cdr of the last pair is the last -argument unless there is only one argument, when the result is just that -argument. Sometimes called @code{cons*}. E.g.:@refill -@lisp -(list* 1) - @result{} 1 -(list* 1 2 3) - @result{} (1 2 . 3) -(list* 1 2 '(3 4)) - @result{} (1 2 3 4) -(list* @var{args} '()) - @equiv{} (list @var{args}) -@end lisp -@end defun +@deffn {procedure+} wt-tree/delete wt-tree key +Returns a new tree containing all the associations in @var{wt-tree}, +except that if @var{wt-tree} contains an association for @var{key}, it +is removed from the result. The average and worst-case times required +by this operation are proportional to the logarithm of the number of +associations in @var{wt-tree}. +@end deffn -@defun copy-list lst -@code{copy-list} makes a copy of @var{lst} using new pairs and returns -it. Only the top level of the list is copied, i.e., pairs forming -elements of the copied list remain @code{eq?} to the corresponding -elements of the original; the copy is, however, not @code{eq?} to the -original, but is @code{equal?} to it.@refill +@deffn {procedure+} wt-tree/delete! wt-tree key +If @var{wt-tree} contains an association for @var{key} the association +is removed. Returns an unspecified value. The average and worst-case +times required by this operation are proportional to the logarithm of +the number of associations in @var{wt-tree}. +@end deffn -Example: -@lisp -(copy-list '(foo foo foo)) - @result{} (foo foo foo) -(define q '(foo bar baz bang)) -(define p q) -(eq? p q) - @result{} #t -(define r (copy-list q)) -(eq? q r) - @result{} #f -(equal? q r) - @result{} #t -(define bar '(bar)) -(eq? bar (car (copy-list (list bar 'foo)))) -@result{} #t - @end lisp -@end defun +@node Advanced Operations on Weight-Balanced Trees, Indexing Operations on Weight-Balanced Trees, Basic Operations on Weight-Balanced Trees, Weight-Balanced Trees +@subsection Advanced Operations on Weight-Balanced Trees + +In the following the @emph{size} of a tree is the number of associations +that the tree contains, and a @emph{smaller} tree contains fewer +associations. +@deffn {procedure+} wt-tree/split< wt-tree bound +Returns a new tree containing all and only the associations in +@var{wt-tree} which have a key that is less than @var{bound} in the +ordering relation of the tree type of @var{wt-tree}. The average and +worst-case times required by this operation are proportional to the +logarithm of the size of @var{wt-tree}. +@end deffn +@deffn {procedure+} wt-tree/split> wt-tree bound +Returns a new tree containing all and only the associations in +@var{wt-tree} which have a key that is greater than @var{bound} in the +ordering relation of the tree type of @var{wt-tree}. The average and +worst-case times required by this operation are proportional to the +logarithm of size of @var{wt-tree}. +@end deffn +@deffn {procedure+} wt-tree/union wt-tree-1 wt-tree-2 +Returns a new tree containing all the associations from both trees. +This operation is asymmetric: when both trees have an association for +the same key, the returned tree associates the datum from @var{wt-tree-2} +with the key. Thus if the trees are viewed as discrete maps then +@code{wt-tree/union} computes the map override of @var{wt-tree-1} by +@var{wt-tree-2}. If the trees are viewed as sets the result is the set +union of the arguments. +The worst-case time required by this operation +is proportional to the sum of the sizes of both trees. +If the minimum key of one tree is greater than the maximum key of +the other tree then the time required is at worst proportional to +the logarithm of the size of the larger tree. +@end deffn +@deffn {procedure+} wt-tree/intersection wt-tree-1 wt-tree-2 +Returns a new tree containing all and only those associations from +@var{wt-tree-1} which have keys appearing as the key of an association +in @var{wt-tree-2}. Thus the associated data in the result are those +from @var{wt-tree-1}. If the trees are being used as sets the result is +the set intersection of the arguments. As a discrete map operation, +@code{wt-tree/intersection} computes the domain restriction of +@var{wt-tree-1} to (the domain of) @var{wt-tree-2}. +The time required by this operation is never worse that proportional to +the sum of the sizes of the trees. +@end deffn -@node Lists as sets, Lists as sequences, List construction, Common List Functions -@subsection Lists as sets +@deffn {procedure+} wt-tree/difference wt-tree-1 wt-tree-2 +Returns a new tree containing all and only those associations from +@var{wt-tree-1} which have keys that @emph{do not} appear as the key of +an association in @var{wt-tree-2}. If the trees are viewed as sets the +result is the asymmetric set difference of the arguments. As a discrete +map operation, it computes the domain restriction of @var{wt-tree-1} to +the complement of (the domain of) @var{wt-tree-2}. +The time required by this operation is never worse that proportional to +the sum of the sizes of the trees. +@end deffn -@code{eq?} is used to test for membership by all the procedures below -which treat lists as sets.@refill -@defun adjoin e l -@code{adjoin} returns the adjoint of the element @var{e} and the list -@var{l}. That is, if @var{e} is in @var{l}, @code{adjoin} returns -@var{l}, otherwise, it returns @code{(cons @var{e} @var{l})}.@refill +@deffn {procedure+} wt-tree/subset? wt-tree-1 wt-tree-2 +Returns @code{#t} iff the key of each association in @var{wt-tree-1} is +the key of some association in @var{wt-tree-2}, otherwise returns @code{#f}. +Viewed as a set operation, @code{wt-tree/subset?} is the improper subset +predicate. +A proper subset predicate can be constructed: -Example: -@lisp -(adjoin 'baz '(bar baz bang)) - @result{} (bar baz bang) -(adjoin 'foo '(bar baz bang)) - @result{} (foo bar baz bang) -@end lisp -@end defun +@example +(define (proper-subset? s1 s2) + (and (wt-tree/subset? s1 s2) + (< (wt-tree/size s1) (wt-tree/size s2)))) +@end example -@defun union l1 l2 -@code{union} returns the combination of @var{l1} and @var{l2}. -Duplicates between @var{l1} and @var{l2} are culled. Duplicates within -@var{l1} or within @var{l2} may or may not be removed.@refill +As a discrete map operation, @code{wt-tree/subset?} is the subset +test on the domain(s) of the map(s). In the worst-case the time +required by this operation is proportional to the size of +@var{wt-tree-1}. +@end deffn -Example: -@lisp -(union '(1 2 3 4) '(5 6 7 8)) - @result{} (4 3 2 1 5 6 7 8) -(union '(1 2 3 4) '(3 4 5 6)) - @result{} (2 1 3 4 5 6) -@end lisp -@end defun -@defun intersection l1 l2 -@code{intersection} returns all elements that are in both @var{l1} and -@var{l2}.@refill +@deffn {procedure+} wt-tree/set-equal? wt-tree-1 wt-tree-2 +Returns @code{#t} iff for every association in @var{wt-tree-1} there is +an association in @var{wt-tree-2} that has the same key, and @emph{vice +versa}. -Example: -@lisp -(intersection '(1 2 3 4) '(3 4 5 6)) - @result{} (3 4) -(intersection '(1 2 3 4) '(5 6 7 8)) - @result{} () -@end lisp -@end defun +Viewing the arguments as sets @code{wt-tree/set-equal?} is the set +equality predicate. As a map operation it determines if two maps are +defined on the same domain. -@defun set-difference l1 l2 -@code{set-difference} returns the union of all elements that are in -@var{l1} but not in @var{l2}.@refill +This procedure is equivalent to -Example: -@lisp -(set-difference '(1 2 3 4) '(3 4 5 6)) - @result{} (1 2) -(set-difference '(1 2 3 4) '(1 2 3 4 5 6)) - @result{} () -@end lisp -@end defun +@example +(lambda (wt-tree-1 wt-tree-2) + (and (wt-tree/subset? wt-tree-1 wt-tree-2 + (wt-tree/subset? wt-tree-2 wt-tree-1))) +@end example -@defun member-if pred lst -@code{member-if} returns @var{lst} if @code{(@var{pred} @var{element})} -is @code{#t} for any @var{element} in @var{lst}. Returns @code{#f} if -@var{pred} does not apply to any @var{element} in @var{lst}.@refill +In the worst-case the time required by this operation is proportional to +the size of the smaller tree. +@end deffn -Example: -@lisp -(member-if vector? '(1 2 3 4)) - @result{} #f -(member-if number? '(1 2 3 4)) - @result{} (1 2 3 4) -@end lisp -@end defun -@defun some pred lst . more-lsts -@var{pred} is a boolean function of as many arguments as there are list -arguments to @code{some} i.e., @var{lst} plus any optional arguments. -@var{pred} is applied to successive elements of the list arguments in -order. @code{some} returns @code{#t} as soon as one of these -applications returns @code{#t}, and is @code{#f} if none returns -@code{#t}. All the lists should have the same length.@refill +@deffn {procedure+} wt-tree/fold combiner initial wt-tree +This procedure reduces @var{wt-tree} by combining all the associations, +using an reverse in-order traversal, so the associations are visited in +reverse order. @var{Combiner} is a procedure of three arguments: a key, +a datum and the accumulated result so far. Provided @var{combiner} +takes time bounded by a constant, @code{wt-tree/fold} takes time +proportional to the size of @var{wt-tree}. +A sorted association list can be derived simply: -Example: -@lisp -(some odd? '(1 2 3 4)) - @result{} #t +@example +(wt-tree/fold (lambda (key datum list) + (cons (cons key datum) list)) + '() + @var{wt-tree})) +@end example -(some odd? '(2 4 6 8)) - @result{} #f +The data in the associations can be summed like this: -(some > '(2 3) '(1 4)) - @result{} #f -@end lisp -@end defun +@example +(wt-tree/fold (lambda (key datum sum) (+ sum datum)) + 0 + @var{wt-tree}) +@end example +@end deffn -@defun every pred lst . more-lsts -@code{every} is analogous to @code{some} except it returns @code{#t} if -every application of @var{pred} is @code{#t} and @code{#f} -otherwise.@refill +@deffn {procedure+} wt-tree/for-each action wt-tree +This procedure traverses the tree in-order, applying @var{action} to +each association. +The associations are processed in increasing order of their keys. +@var{Action} is a procedure of two arguments which take the key and +datum respectively of the association. +Provided @var{action} takes time bounded by a constant, +@code{wt-tree/for-each} takes time proportional to in the size of +@var{wt-tree}. +The example prints the tree: -Example: -@lisp -(every even? '(1 2 3 4)) - @result{} #f +@example +(wt-tree/for-each (lambda (key value) + (display (list key value))) + @var{wt-tree})) +@end example +@end deffn -(every even? '(2 4 6 8)) - @result{} #t -(every > '(2 3) '(1 4)) - @result{} #f -@end lisp -@end defun +@node Indexing Operations on Weight-Balanced Trees, , Advanced Operations on Weight-Balanced Trees, Weight-Balanced Trees +@subsection Indexing Operations on Weight-Balanced Trees -@defun notany pred . lst -@code{notany} is analogous to @code{some} but returns @code{#t} if no -application of @var{pred} returns @code{#t} or @code{#f} as soon as any -one does.@refill -@end defun +Weight balanced trees support operations that view the tree as sorted +sequence of associations. Elements of the sequence can be accessed by +position, and the position of an element in the sequence can be +determined, both in logarthmic time. -@defun notevery pred . lst -@code{notevery} is analogous to @code{some} but returns @code{#t} as soon -as an application of @var{pred} returns @code{#f}, and @code{#f} -otherwise.@refill +@deffn {procedure+} wt-tree/index wt-tree index +@deffnx {procedure+} wt-tree/index-datum wt-tree index +@deffnx {procedure+} wt-tree/index-pair wt-tree index +Returns the 0-based @var{index}th association of @var{wt-tree} in the +sorted sequence under the tree's ordering relation on the keys. +@code{wt-tree/index} returns the @var{index}th key, +@code{wt-tree/index-datum} returns the datum associated with the +@var{index}th key and @code{wt-tree/index-pair} returns a new pair +@code{(@var{key} . @var{datum})} which is the @code{cons} of the @var{index}th +key and its datum. The average and worst-case times required by this +operation are proportional to the logarithm of the number of +associations in the tree. -Example: -@lisp -(notevery even? '(1 2 3 4)) - @result{} #t +These operations signal an error if the tree is empty, if +@var{index}@code{<0}, or if @var{index} is greater than or equal to the +number of associations in the tree. -(notevery even? '(2 4 6 8)) - @result{} #f -@end lisp -@end defun +Indexing can be used to find the median and maximum keys in the tree as +follows: -@defun find-if pred lst -@code{find-if} searches for the first @var{element} in @var{lst} such -that @code{(@var{pred} @var{element})} returns @code{#t}. If it finds -any such @var{element} in @var{lst}, @var{element} is returned. -Otherwise, @code{#f} is returned.@refill +@example +median: (wt-tree/index @var{wt-tree} (quotient (wt-tree/size @var{wt-tree}) 2)) -Example: -@lisp -(find-if number? '(foo 1 bar 2)) - @result{} 1 +maximum: (wt-tree/index @var{wt-tree} (-1+ (wt-tree/size @var{wt-tree}))) +@end example +@end deffn -(find-if number? '(foo bar baz bang)) - @result{} #f +@deffn {procedure+} wt-tree/rank wt-tree key +Determines the 0-based position of @var{key} in the sorted sequence of +the keys under the tree's ordering relation, or @code{#f} if the tree +has no association with for @var{key}. This procedure returns either an +exact non-negative integer or @code{#f}. The average and worst-case +times required by this operation are proportional to the logarithm of +the number of associations in the tree. +@end deffn -(find-if symbol? '(1 2 foo bar)) - @result{} foo -@end lisp -@end defun +@deffn {procedure+} wt-tree/min wt-tree +@deffnx {procedure+} wt-tree/min-datum wt-tree +@deffnx {procedure+} wt-tree/min-pair wt-tree +Returns the association of @var{wt-tree} that has the least key under the tree's ordering relation. +@code{wt-tree/min} returns the least key, +@code{wt-tree/min-datum} returns the datum associated with the +least key and @code{wt-tree/min-pair} returns a new pair +@code{(key . datum)} which is the @code{cons} of the minimum key and its datum. +The average and worst-case times required by this operation are +proportional to the logarithm of the number of associations in the tree. -@defun remove elt lst -@code{remove} removes all occurrences of @var{elt} from @var{lst} using -@code{eqv?} to test for equality and returns everything that's left. -N.B.: other implementations (Chez, Scheme->C and T, at least) use -@code{equal?} as the equality test.@refill +These operations signal an error if the tree is empty. +They could be written +@example +(define (wt-tree/min tree) (wt-tree/index tree 0)) +(define (wt-tree/min-datum tree) (wt-tree/index-datum tree 0)) +(define (wt-tree/min-pair tree) (wt-tree/index-pair tree 0)) +@end example +@end deffn -Example: -@lisp -(remove 1 '(1 2 1 3 1 4 1 5)) - @result{} (2 3 4 5) +@deffn {procedure+} wt-tree/delete-min wt-tree +Returns a new tree containing all of the associations in @var{wt-tree} +except the association with the least key under the @var{wt-tree}'s +ordering relation. An error is signalled if the tree is empty. The +average and worst-case times required by this operation are proportional +to the logarithm of the number of associations in the tree. This +operation is equivalent to -(remove 'foo '(bar baz bang)) - @result{} (bar baz bang) -@end lisp -@end defun +@example +(wt-tree/delete @var{wt-tree} (wt-tree/min @var{wt-tree})) +@end example +@end deffn -@defun remove-if pred lst -@code{remove-if} removes all @var{element}s from @var{lst} where -@code{(@var{pred} @var{element})} is @code{#t} and returns everything -that's left.@refill -Example: -@lisp -(remove-if number? '(1 2 3 4)) - @result{} () +@deffn {procedure+} wt-tree/delete-min! wt-tree +Removes the association with the least key under the @var{wt-tree}'s +ordering relation. An error is signalled if the tree is empty. The +average and worst-case times required by this operation are proportional +to the logarithm of the number of associations in the tree. This +operation is equivalent to -(remove-if even? '(1 2 3 4 5 6 7 8)) - @result{} (1 3 5 7) -@end lisp -@end defun +@example +(wt-tree/delete! @var{wt-tree} (wt-tree/min @var{wt-tree})) +@end example +@end deffn -@defun remove-if-not pred lst -@code{remove-if-not} removes all @var{element}s from @var{lst} for which -@code{(@var{pred} @var{element})} is @code{#f} and returns everything that's -left.@refill -Example: -@lisp -(remove-if-not number? '(foo bar baz)) - @result{} () -(remove-if-not odd? '(1 2 3 4 5 6 7 8)) - @result{} (1 3 5 7) -@end lisp -@end defun +@node Other Packages, About SLIB, Database Packages, Top +@chapter Other Packages -@defun has-duplicates? lst -returns @code{#t} if 2 members of @var{lst} are @code{equal?}, @code{#f} -otherwise. -Example: -@lisp -(has-duplicates? '(1 2 3 4)) - @result{} #f +@menu +* Data Structures:: Various data structures. +* Procedures:: Miscellaneous utility procedures. +* Standards Support:: Support for Scheme Standards. +* Session Support:: REPL and Debugging. +* Extra-SLIB Packages:: +@end menu -(has-duplicates? '(2 4 3 4)) - @result{} #t -@end lisp -@end defun +@node Data Structures, Procedures, Other Packages, Other Packages +@section Data Structures -@node Lists as sequences, Destructive list operations, Lists as sets, Common List Functions -@subsection Lists as sequences -@defun position obj lst -@code{position} returns the 0-based position of @var{obj} in @var{lst}, -or @code{#f} if @var{obj} does not occur in @var{lst}.@refill -Example: -@lisp -(position 'foo '(foo bar baz bang)) - @result{} 0 -(position 'baz '(foo bar baz bang)) - @result{} 2 -(position 'oops '(foo bar baz bang)) - @result{} #f -@end lisp -@end defun +@menu +* Arrays:: 'array +* Array Mapping:: 'array-for-each +* Association Lists:: 'alist +* Byte:: 'byte +* Collections:: 'collect +* Dynamic Data Type:: 'dynamic +* Hash Tables:: 'hash-table +* Hashing:: 'hash, 'sierpinski, 'soundex +* Priority Queues:: 'priority-queue +* Queues:: 'queue +* Records:: 'record +* Structures:: 'struct, 'structure +@end menu -@defun reduce p lst -@code{reduce} combines all the elements of a sequence using a binary -operation (the combination is left-associative). For example, using -@code{+}, one can add up all the elements. @code{reduce} allows you to -apply a function which accepts only two arguments to more than 2 -objects. Functional programmers usually refer to this as @dfn{foldl}. -@code{collect:reduce} (@xref{Collections}) provides a version of -@code{collect} generalized to collections.@refill -Example: -@lisp -(reduce + '(1 2 3 4)) - @result{} 10 -(define (bad-sum . l) (reduce + l)) -(bad-sum 1 2 3 4) - @equiv{} (reduce + (1 2 3 4)) - @equiv{} (+ (+ (+ 1 2) 3) 4) -@result{} 10 -(bad-sum) - @equiv{} (reduce + ()) - @result{} () -(reduce string-append '("hello" "cruel" "world")) - @equiv{} (string-append (string-append "hello" "cruel") "world") - @result{} "hellocruelworld" -(reduce anything '()) - @result{} () -(reduce anything '(x)) - @result{} x -@end lisp -What follows is a rather non-standard implementation of @code{reverse} -in terms of @code{reduce} and a combinator elsewhere called -@dfn{C}.@refill -@lisp -;;; Contributed by Jussi Piitulainen (jpiitula@@ling.helsinki.fi) +@node Arrays, Array Mapping, Data Structures, Data Structures +@subsection Arrays -(define commute - (lambda (f) - (lambda (x y) - (f y x)))) +@code{(require 'array)} +@ftindex array -(define reverse - (lambda (args) - (reduce-init (commute cons) args))) -@end lisp +@defun array? obj +Returns @code{#t} if the @var{obj} is an array, and @code{#f} if not. @end defun -@defun reduce-init p init lst -@code{reduce-init} is the same as reduce, except that it implicitly -inserts @var{init} at the start of the list. @code{reduce-init} is -preferred if you want to handle the null list, the one-element, and -lists with two or more elements consistently. It is common to use the -operator's idempotent as the initializer. Functional programmers -usually call this @dfn{foldl}.@refill +@defun make-array initial-value bound1 bound2 @dots{} +Creates and returns an array that has as many dimensins as there are +@var{bound}s and fills it with @var{initial-value}.@refill +@end defun -Example: +When constructing an array, @var{bound} is either an inclusive range of +indices expressed as a two element list, or an upper bound expressed as +a single integer. So@refill @lisp -(define (sum . l) (reduce-init + 0 l)) -(sum 1 2 3 4) - @equiv{} (reduce-init + 0 (1 2 3 4)) - @equiv{} (+ (+ (+ (+ 0 1) 2) 3) 4) - @result{} 10 -(sum) - @equiv{} (reduce-init + 0 '()) - @result{} 0 - -(reduce-init string-append "@@" '("hello" "cruel" "world")) -@equiv{} -(string-append (string-append (string-append "@@" "hello") - "cruel") - "world") -@result{} "@@hellocruelworld" +(make-array 'foo 3 3) @equiv{} (make-array 'foo '(0 2) '(0 2)) @end lisp -Given a differentiation of 2 arguments, @code{diff}, the following will -differentiate by any number of variables. +@defun make-shared-array array mapper bound1 bound2 @dots{} +@code{make-shared-array} can be used to create shared subarrays of other +arrays. The @var{mapper} is a function that translates coordinates in +the new array into coordinates in the old array. A @var{mapper} must be +linear, and its range must stay within the bounds of the old array, but +it can be otherwise arbitrary. A simple example:@refill @lisp -(define (diff* exp . vars) - (reduce-init diff exp vars)) +(define fred (make-array #f 8 8)) +(define freds-diagonal + (make-shared-array fred (lambda (i) (list i i)) 8)) +(array-set! freds-diagonal 'foo 3) +(array-ref fred 3 3) + @result{} FOO +(define freds-center + (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) + 2 2)) +(array-ref freds-center 0 0) + @result{} FOO @end lisp - -Example: -@lisp -;;; Real-world example: Insertion sort using reduce-init. - -(define (insert l item) - (if (null? l) - (list item) - (if (< (car l) item) - (cons (car l) (insert (cdr l) item)) - (cons item l)))) -(define (insertion-sort l) (reduce-init insert '() l)) - -(insertion-sort '(3 1 4 1 5) - @equiv{} (reduce-init insert () (3 1 4 1 5)) - @equiv{} (insert (insert (insert (insert (insert () 3) 1) 4) 1) 5) - @equiv{} (insert (insert (insert (insert (3)) 1) 4) 1) 5) - @equiv{} (insert (insert (insert (1 3) 4) 1) 5) - @equiv{} (insert (insert (1 3 4) 1) 5) - @equiv{} (insert (1 1 3 4) 5) - @result{} (1 1 3 4 5) - @end lisp @end defun -@defun butlast lst n -@code{butlast} returns all but the last @var{n} elements of -@var{lst}.@refill - -Example: -@lisp -(butlast '(1 2 3 4) 3) - @result{} (1) -(butlast '(1 2 3 4) 4) - @result{} () -@end lisp +@defun array-rank obj +Returns the number of dimensions of @var{obj}. If @var{obj} is not an +array, 0 is returned. @end defun -@defun nthcdr n lst -@code{nthcdr} takes @var{n} @code{cdr}s of @var{lst} and returns the -result. Thus @code{(nthcdr 3 @var{lst})} @equiv{} @code{(cdddr -@var{lst})} - -Example: +@defun array-shape array +@code{array-shape} returns a list of inclusive bounds. So: @lisp -(nthcdr 2 '(1 2 3 4)) - @result{} (3 4) -(nthcdr 0 '(1 2 3 4)) - @result{} (1 2 3 4) +(array-shape (make-array 'foo 3 5)) + @result{} ((0 2) (0 4)) @end lisp @end defun -@defun last lst n -@code{last} returns the last @var{n} elements of @var{lst}. @var{n} -must be a non-negative integer. - -Example: -@lisp -(last '(foo bar baz bang) 2) - @result{} (baz bang) -(last '(1 2 3) 0) - @result{} 0 +@defun array-dimensions array +@code{array-dimensions} is similar to @code{array-shape} but replaces +elements with a 0 minimum with one greater than the maximum. So: +@lisp +(array-dimensions (make-array 'foo 3 5)) + @result{} (3 5) @end lisp @end defun +@deffn Procedure array-in-bounds? array index1 index2 @dots{} +Returns @code{#t} if its arguments would be acceptable to +@code{array-ref}. +@end deffn +@defun array-ref array index1 index2 @dots{} +Returns the element at the @code{(@var{index1}, @var{index2})} element +in @var{array}.@refill +@end defun +@deffn Procedure array-set! array new-value index1 index2 @dots{} +@end deffn +@defun array-1d-ref array index +@defunx array-2d-ref array index index +@defunx array-3d-ref array index index index +@end defun +@deffn Procedure array-1d-set! array new-value index +@deffnx Procedure array-2d-set! array new-value index index +@deffnx Procedure array-3d-set! array new-value index index index +@end deffn -@node Destructive list operations, Non-List functions, Lists as sequences, Common List Functions -@subsection Destructive list operations +The functions are just fast versions of @code{array-ref} and +@code{array-set!} that take a fixed number of arguments, and perform no +bounds checking.@refill -These procedures may mutate the list they operate on, but any such -mutation is undefined. +If you comment out the bounds checking code, this is about as efficient +as you could ask for without help from the compiler. -@deffn Procedure nconc args -@code{nconc} destructively concatenates its arguments. (Compare this -with @code{append}, which copies arguments rather than destroying them.) -Sometimes called @code{append!} (@xref{Rev2 Procedures}).@refill +An exercise left to the reader: implement the rest of APL. -Example: You want to find the subsets of a set. Here's the obvious way: -@lisp -(define (subsets set) - (if (null? set) - '(()) - (append (mapcar (lambda (sub) (cons (car set) sub)) - (subsets (cdr set))) - (subsets (cdr set))))) -@end lisp -But that does way more consing than you need. Instead, you could -replace the @code{append} with @code{nconc}, since you don't have any -need for all the intermediate results.@refill -Example: -@lisp -(define x '(a b c)) -(define y '(d e f)) -(nconc x y) - @result{} (a b c d e f) -x - @result{} (a b c d e f) -@end lisp +@node Array Mapping, Association Lists, Arrays, Data Structures +@subsection Array Mapping -@code{nconc} is the same as @code{append!} in @file{sc2.scm}. -@end deffn +@code{(require 'array-for-each)} +@ftindex array-for-each -@deffn Procedure nreverse lst -@code{nreverse} reverses the order of elements in @var{lst} by mutating -@code{cdr}s of the list. Sometimes called @code{reverse!}.@refill +@defun array-map! array0 proc array1 @dots{} +@var{array1}, @dots{} must have the same number of dimensions as +@var{array0} and have a range for each index which includes the range +for the corresponding index in @var{array0}. @var{proc} is applied to +each tuple of elements of @var{array1} @dots{} and the result is stored +as the corresponding element in @var{array0}. The value returned is +unspecified. The order of application is unspecified. +@end defun -Example: -@lisp -(define foo '(a b c)) -(nreverse foo) - @result{} (c b a) -foo - @result{} (a) -@end lisp +@defun array-for-each @var{proc} @var{array0} @dots{} +@var{proc} is applied to each tuple of elements of @var{array0} @dots{} +in row-major order. The value returned is unspecified. +@end defun -Some people have been confused about how to use @code{nreverse}, -thinking that it doesn't return a value. It needs to be pointed out -that@refill -@lisp -(set! lst (nreverse lst)) -@end lisp -@noindent -is the proper usage, not -@lisp -(nreverse lst) -@end lisp -The example should suffice to show why this is the case. -@end deffn +@defun array-indexes @var{array} +Returns an array of lists of indexes for @var{array} such that, if +@var{li} is a list of indexes for which @var{array} is defined, (equal? +@var{li} (apply array-ref (array-indexes @var{array}) @var{li})). +@end defun -@deffn Procedure delete elt lst -@deffnx Procedure delete-if pred lst -@deffnx Procedure delete-if-not pred lst -Destructive versions of @code{remove} @code{remove-if}, and -@code{remove-if-not}.@refill +@defun array-index-map! array proc +applies @var{proc} to the indices of each element of @var{array} in +turn, storing the result in the corresponding element. The value +returned and the order of application are unspecified. -Example: -@lisp -(define lst '(foo bar baz bang)) -(delete 'foo lst) - @result{} (bar baz bang) -lst - @result{} (foo bar baz bang) +One can implement @var{array-indexes} as +@example +(define (array-indexes array) + (let ((ra (apply make-array #f (array-shape array)))) + (array-index-map! ra (lambda x x)) + ra)) +@end example +Another example: +@example +(define (apl:index-generator n) + (let ((v (make-uniform-vector n 1))) + (array-index-map! v (lambda (i) i)) + v)) +@end example +@end defun -(define lst '(1 2 3 4 5 6 7 8 9)) -(delete-if odd? lst) - @result{} (2 4 6 8) -lst - @result{} (1 2 4 6 8) -@end lisp +@defun array-copy! source destination +Copies every element from vector or array @var{source} to the +corresponding element of @var{destination}. @var{destination} must have +the same rank as @var{source}, and be at least as large in each +dimension. The order of copying is unspecified. +@end defun -Some people have been confused about how to use @code{delete}, -@code{delete-if}, and @code{delete-if}, thinking that they dont' return -a value. It needs to be pointed out that@refill -@lisp -(set! lst (delete el lst)) -@end lisp -@noindent -is the proper usage, not -@lisp -(delete el lst) -@end lisp -The examples should suffice to show why this is the case. -@end deffn +@node Association Lists, Byte, Array Mapping, Data Structures +@subsection Association Lists +@code{(require 'alist)} +@ftindex alist -@node Non-List functions, , Destructive list operations, Common List Functions -@subsection Non-List functions +Alist functions provide utilities for treating a list of key-value pairs +as an associative database. These functions take an equality predicate, +@var{pred}, as an argument. This predicate should be repeatable, +symmetric, and transitive.@refill -@defun and? . args -@code{and?} checks to see if all its arguments are true. If they are, -@code{and?} returns @code{#t}, otherwise, @code{#f}. (In contrast to -@code{and}, this is a function, so all arguments are always evaluated -and in an unspecified order.)@refill +Alist functions can be used with a secondary index method such as hash +tables for improved performance. -Example: -@lisp -(and? 1 2 3) - @result{} #t -(and #f 1 2) - @result{} #f -@end lisp +@defun predicate->asso pred +Returns an @dfn{association function} (like @code{assq}, @code{assv}, or +@code{assoc}) corresponding to @var{pred}. The returned function +returns a key-value pair whose key is @code{pred}-equal to its first +argument or @code{#f} if no key in the alist is @var{pred}-equal to the +first argument.@refill @end defun -@defun or? . args -@code{or?} checks to see if any of its arguments are true. If any is -true, @code{or?} returns @code{#t}, and @code{#f} otherwise. (To -@code{or} as @code{and?} is to @code{and}.)@refill +@defun alist-inquirer pred +Returns a procedure of 2 arguments, @var{alist} and @var{key}, which +returns the value associated with @var{key} in @var{alist} or @code{#f} if +@var{key} does not appear in @var{alist}.@refill +@end defun -Example: +@defun alist-associator pred +Returns a procedure of 3 arguments, @var{alist}, @var{key}, and +@var{value}, which returns an alist with @var{key} and @var{value} +associated. Any previous value associated with @var{key} will be +lost. This returned procedure may or may not have side effects on its +@var{alist} argument. An example of correct usage is:@refill @lisp -(or? 1 2 #f) - @result{} #t -(or? #f #f #f) - @result{} #f +(define put (alist-associator string-ci=?)) +(define alist '()) +(set! alist (put alist "Foo" 9)) @end lisp @end defun -@defun atom? object -Returns @code{#t} if @var{object} is not a pair and @code{#f} if it is -pair. (Called @code{atom} in Common LISP.) +@defun alist-remover pred +Returns a procedure of 2 arguments, @var{alist} and @var{key}, which +returns an alist with an association whose @var{key} is key removed. +This returned procedure may or may not have side effects on its +@var{alist} argument. An example of correct usage is:@refill @lisp -(atom? 1) - @result{} #t -(atom? '(1 2)) - @result{} #f -(atom? #(1 2)) ; dubious! - @result{} #t +(define rem (alist-remover string-ci=?)) +(set! alist (rem alist "foo")) @end lisp @end defun -@defun type-of object -Returns a symbol name for the type of @var{object}. +@defun alist-map proc alist +Returns a new association list formed by mapping @var{proc} over the +keys and values of @var{alist}. @var{proc} must be a function of 2 +arguments which returns the new value part. @end defun -@defun coerce object result-type -Converts and returns @var{object} of type @code{char}, @code{number}, -@code{string}, @code{symbol}, @code{list}, or @code{vector} to -@var{result-type} (which must be one of these symbols). +@defun alist-for-each proc alist +Applies @var{proc} to each pair of keys and values of @var{alist}. +@var{proc} must be a function of 2 arguments. The returned value is +unspecified. @end defun -@node Format, Generic-Write, Common List Functions, Procedures -@section Format +@node Byte, Collections, Association Lists, Data Structures +@subsection Byte -@code{(require 'format)} +@code{(require 'byte)} -@menu -* Format Interface:: -* Format Specification:: -@end menu +Some algorithms are expressed in terms of arrays of small integers. +Using Scheme strings to implement these arrays is not portable vis-a-vis +the correspondence between integers and characters and non-ascii +character sets. These functions abstract the notion of a @dfn{byte}. +@cindex byte -@node Format Interface, Format Specification, Format, Format -@subsection Format Interface +@deffn Function byte-ref bytes k +@var{k} must be a valid index of @var{bytes}. @code{byte-ref} returns +byte @var{k} of @var{bytes} using zero-origin indexing. +@findex byte-ref +@end deffn -@defun format destination format-string . arguments -An almost complete implementation of Common LISP format description -according to the CL reference book @cite{Common LISP} from Guy L. -Steele, Digital Press. Backward compatible to most of the available -Scheme format implementations. +@deffn Procedure byte-set! bytes k byte +@var{k} must be a valid index of @var{bytes}%, and @var{byte} must be a +small integer. @code{Byte-set!} stores @var{byte} in element @var{k} +of @var{bytes} +@findex byte-set! +and returns an unspecified value. @c -Returns @code{#t}, @code{#f} or a string; has side effect of printing -according to @var{format-string}. If @var{destination} is @code{#t}, -the output is to the current output port and @code{#t} is returned. If -@var{destination} is @code{#f}, a formatted string is returned as the -result of the call. NEW: If @var{destination} is a string, -@var{destination} is regarded as the format string; @var{format-string} is -then the first argument and the output is returned as a string. If -@var{destination} is a number, the output is to the current error port -if available by the implementation. Otherwise @var{destination} must be -an output port and @code{#t} is returned.@refill +@end deffn -@var{format-string} must be a string. In case of a formatting error -format returns @code{#f} and prints a message on the current output or -error port. Characters are output as if the string were output by the -@code{display} function with the exception of those prefixed by a tilde -(~). For a detailed description of the @var{format-string} syntax -please consult a Common LISP format reference manual. For a test suite -to verify this format implementation load @file{formatst.scm}. Please -send bug reports to @code{lutzeb@@cs.tu-berlin.de}. +@deffn Function make-bytes k +@deffnx Function make-bytes k byte + +@code{Make-bytes} returns a newly allocated byte-array of +@findex make-bytes +length @var{k}. If @var{byte} is given, then all elements of the +byte-array are initialized to @var{byte}, otherwise the contents of the +byte-array are unspecified. -Note: @code{format} is not reentrant, i.e. only one @code{format}-call -may be executed at a time. +@end deffn -@end defun +@deffn Function write-byte byte +@deffnx Function write-byte byte port -@node Format Specification, , Format Interface, Format -@subsection Format Specification (Format version 3.0) +Writes the byte @var{byte} (not an external representation of the +byte) to the given @var{port} and returns an unspecified value. The +@var{port} argument may be omitted, in which case it defaults to the value +returned by @code{current-output-port}. +@findex current-output-port -Please consult a Common LISP format reference manual for a detailed -description of the format string syntax. For a demonstration of the -implemented directives see @file{formatst.scm}.@refill +@end deffn -This implementation supports directive parameters and modifiers -(@code{:} and @code{@@} characters). Multiple parameters must be -separated by a comma (@code{,}). Parameters can be numerical parameters -(positive or negative), character parameters (prefixed by a quote -character (@code{'}), variable parameters (@code{v}), number of rest -arguments parameter (@code{#}), empty and default parameters. Directive -characters are case independent. The general form of a directive -is:@refill +@deffn Function read-byte +@deffnx Function read-byte port -@noindent -@var{directive} ::= ~@{@var{directive-parameter},@}[:][@@]@var{directive-character} +Returns the next byte available from the input @var{port}, updating +the @var{port} to point to the following byte. If no more bytes +are available, an end of file object is returned. @var{Port} may be +omitted, in which case it defaults to the value returned by +@code{current-input-port}. +@findex current-input-port -@noindent -@var{directive-parameter} ::= [ [-|+]@{0-9@}+ | '@var{character} | v | # ] +@end deffn +@deffn Function bytes byte @dots{} -@subsubsection Implemented CL Format Control Directives +Returns a newly allocated byte-array composed of the arguments. -Documentation syntax: Uppercase characters represent the corresponding -control directive characters. Lowercase characters represent control -directive parameter descriptions. +@end deffn -@table @asis -@item @code{~A} -Any (print as @code{display} does). -@table @asis -@item @code{~@@A} -left pad. -@item @code{~@var{mincol},@var{colinc},@var{minpad},@var{padchar}A} -full padding. -@end table -@item @code{~S} -S-expression (print as @code{write} does). -@table @asis -@item @code{~@@S} -left pad. -@item @code{~@var{mincol},@var{colinc},@var{minpad},@var{padchar}S} -full padding. -@end table -@item @code{~D} -Decimal. -@table @asis -@item @code{~@@D} -print number sign always. -@item @code{~:D} -print comma separated. -@item @code{~@var{mincol},@var{padchar},@var{commachar}D} -padding. -@end table -@item @code{~X} -Hexadecimal. -@table @asis -@item @code{~@@X} -print number sign always. -@item @code{~:X} -print comma separated. -@item @code{~@var{mincol},@var{padchar},@var{commachar}X} -padding. -@end table -@item @code{~O} -Octal. -@table @asis -@item @code{~@@O} -print number sign always. -@item @code{~:O} -print comma separated. -@item @code{~@var{mincol},@var{padchar},@var{commachar}O} -padding. -@end table -@item @code{~B} -Binary. -@table @asis -@item @code{~@@B} -print number sign always. -@item @code{~:B} -print comma separated. -@item @code{~@var{mincol},@var{padchar},@var{commachar}B} -padding. -@end table -@item @code{~@var{n}R} -Radix @var{n}. -@table @asis -@item @code{~@var{n},@var{mincol},@var{padchar},@var{commachar}R} -padding. -@end table -@item @code{~@@R} -print a number as a Roman numeral. -@item @code{~:R} -print a number as an ordinal English number. -@item @code{~:@@R} -print a number as a cardinal English number. -@item @code{~P} -Plural. -@table @asis -@item @code{~@@P} -prints @code{y} and @code{ies}. -@item @code{~:P} -as @code{~P but jumps 1 argument backward.} -@item @code{~:@@P} -as @code{~@@P but jumps 1 argument backward.} -@end table -@item @code{~C} -Character. -@table @asis -@item @code{~@@C} -prints a character as the reader can understand it (i.e. @code{#\} prefixing). -@item @code{~:C} -prints a character as emacs does (eg. @code{^C} for ASCII 03). -@end table -@item @code{~F} -Fixed-format floating-point (prints a flonum like @var{mmm.nnn}). -@table @asis -@item @code{~@var{width},@var{digits},@var{scale},@var{overflowchar},@var{padchar}F} -@item @code{~@@F} -If the number is positive a plus sign is printed. -@end table -@item @code{~E} -Exponential floating-point (prints a flonum like @var{mmm.nnn@code{E}ee}). -@table @asis -@item @code{~@var{width},@var{digits},@var{exponentdigits},@var{scale},@var{overflowchar},@var{padchar},@var{exponentchar}E} -@item @code{~@@E} -If the number is positive a plus sign is printed. -@end table -@item @code{~G} -General floating-point (prints a flonum either fixed or exponential). -@table @asis -@item @code{~@var{width},@var{digits},@var{exponentdigits},@var{scale},@var{overflowchar},@var{padchar},@var{exponentchar}G} -@item @code{~@@G} -If the number is positive a plus sign is printed. -@end table -@item @code{~$} -Dollars floating-point (prints a flonum in fixed with signs separated). -@table @asis -@item @code{~@var{digits},@var{scale},@var{width},@var{padchar}$} -@item @code{~@@$} -If the number is positive a plus sign is printed. -@item @code{~:@@$} -A sign is always printed and appears before the padding. -@item @code{~:$} -The sign appears before the padding. -@end table -@item @code{~%} -Newline. -@table @asis -@item @code{~@var{n}%} -print @var{n} newlines. -@end table -@item @code{~&} -print newline if not at the beginning of the output line. -@table @asis -@item @code{~@var{n}&} -prints @code{~&} and then @var{n-1} newlines. -@end table -@item @code{~|} -Page Separator. -@table @asis -@item @code{~@var{n}|} -print @var{n} page separators. -@end table -@item @code{~~} -Tilde. -@table @asis -@item @code{~@var{n}~} -print @var{n} tildes. -@end table -@item @code{~} -Continuation Line. -@table @asis -@item @code{~:} -newline is ignored, white space left. -@item @code{~@@} -newline is left, white space ignored. -@end table -@item @code{~T} -Tabulation. -@table @asis -@item @code{~@@T} -relative tabulation. -@item @code{~@var{colnum,colinc}T} -full tabulation. -@end table -@item @code{~?} -Indirection (expects indirect arguments as a list). -@table @asis -@item @code{~@@?} -extracts indirect arguments from format arguments. -@end table -@item @code{~(@var{str}~)} -Case conversion (converts by @code{string-downcase}). -@table @asis -@item @code{~:(@var{str}~)} -converts by @code{string-capitalize}. -@item @code{~@@(@var{str}~)} -converts by @code{string-capitalize-first}. -@item @code{~:@@(@var{str}~)} -converts by @code{string-upcase}. -@end table -@item @code{~*} -Argument Jumping (jumps 1 argument forward). -@table @asis -@item @code{~@var{n}*} -jumps @var{n} arguments forward. -@item @code{~:*} -jumps 1 argument backward. -@item @code{~@var{n}:*} -jumps @var{n} arguments backward. -@item @code{~@@*} -jumps to the 0th argument. -@item @code{~@var{n}@@*} -jumps to the @var{n}th argument (beginning from 0) -@end table -@item @code{~[@var{str0}~;@var{str1}~;...~;@var{strn}~]} -Conditional Expression (numerical clause conditional). -@table @asis -@item @code{~@var{n}[} -take argument from @var{n}. -@item @code{~@@[} -true test conditional. -@item @code{~:[} -if-else-then conditional. -@item @code{~;} -clause separator. -@item @code{~:;} -default clause follows. -@end table -@item @code{~@{@var{str}~@}} -Iteration (args come from the next argument (a list)). -@table @asis -@item @code{~@var{n}@{} -at most @var{n} iterations. -@item @code{~:@{} -args from next arg (a list of lists). -@item @code{~@@@{} -args from the rest of arguments. -@item @code{~:@@@{} -args from the rest args (lists). -@end table -@item @code{~^} -Up and out. -@table @asis -@item @code{~@var{n}^} -aborts if @var{n} = 0 -@item @code{~@var{n},@var{m}^} -aborts if @var{n} = @var{m} -@item @code{~@var{n},@var{m},@var{k}^} -aborts if @var{n} <= @var{m} <= @var{k} -@end table -@end table +@deffn Function bytes->list bytes +@deffnx Function list->bytes bytes + +@code{Bytes->list} returns a newly allocated list of the +@findex bytes->list +bytes that make up the given byte-array. @code{List->bytes} +@findex list->bytes +returns a newly allocated byte-array formed from the small integers in +the list @var{bytes}. @code{Bytes->list} and @code{list->bytes} are +@findex list->bytes +@findex bytes->list +inverses so far as @code{equal?} is concerned. +@findex equal? + +@end deffn -@subsubsection Not Implemented CL Format Control Directives +@node Collections, Dynamic Data Type, Byte, Data Structures +@subsection Collections -@table @asis -@item @code{~:A} -print @code{#f} as an empty list (see below). -@item @code{~:S} -print @code{#f} as an empty list (see below). -@item @code{~<~>} -Justification. -@item @code{~:^} -(sorry I don't understand its semantics completely) -@end table +@c Much of the documentation in this section was written by Dave Love +@c (d.love@dl.ac.uk) -- don't blame Ken Dickey for its faults. +@c but we can blame him for not writing it! +@code{(require 'collect)} +@ftindex collect -@subsubsection Extended, Replaced and Additional Control Directives +Routines for managing collections. Collections are aggregate data +structures supporting iteration over their elements, similar to the +Dylan(TM) language, but with a different interface. They have +@dfn{elements} indexed by corresponding @dfn{keys}, although the keys +may be implicit (as with lists).@refill -@table @asis -@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}D} -@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}X} -@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}O} -@item @code{~@var{mincol},@var{padchar},@var{commachar},@var{commawidth}B} -@item @code{~@var{n},@var{mincol},@var{padchar},@var{commachar},@var{commawidth}R} -@var{commawidth} is the number of characters between two comma characters. -@end table +New types of collections may be defined as YASOS objects (@xref{Yasos}). +They must support the following operations: +@itemize @bullet +@item +@code{(collection? @var{self})} (always returns @code{#t}); -@table @asis -@item @code{~I} -print a R4RS complex number as @code{~F~@@Fi} with passed parameters for -@code{~F}. -@item @code{~Y} -Pretty print formatting of an argument for scheme code lists. -@item @code{~K} -Same as @code{~?.} -@item @code{~!} -Flushes the output if format @var{destination} is a port. -@item @code{~_} -Print a @code{#\space} character -@table @asis -@item @code{~@var{n}_} -print @var{n} @code{#\space} characters. -@end table -@item @code{~/} -Print a @code{#\tab} character -@table @asis -@item @code{~@var{n}/} -print @var{n} @code{#\tab} characters. -@end table -@item @code{~@var{n}C} -Takes @var{n} as an integer representation for a character. No arguments -are consumed. @var{n} is converted to a character by -@code{integer->char}. @var{n} must be a positive decimal number.@refill -@item @code{~:S} -Print out readproof. Prints out internal objects represented as -@code{#<...>} as strings @code{"#<...>"} so that the format output can always -be processed by @code{read}. -@refill -@item @code{~:A} -Print out readproof. Prints out internal objects represented as -@code{#<...>} as strings @code{"#<...>"} so that the format output can always -be processed by @code{read}. -@item @code{~Q} -Prints information and a copyright notice on the format implementation. -@table @asis -@item @code{~:Q} -prints format version. -@end table -@refill -@item @code{~F, ~E, ~G, ~$} -may also print number strings, i.e. passing a number as a string and -format it accordingly. -@end table +@item +@code{(size @var{self})} returns the number of elements in the collection; + +@item +@code{(print @var{self} @var{port})} is a specialized print operation +for the collection which prints a suitable representation on the given +@var{port} or returns it as a string if @var{port} is @code{#t};@refill + +@item +@code{(gen-elts @var{self})} returns a thunk which on successive +invocations yields elements of @var{self} in order or gives an error if +it is invoked more than @code{(size @var{self})} times;@refill + +@item +@code{(gen-keys @var{self})} is like @code{gen-elts}, but yields the +collection's keys in order. + +@end itemize +They might support specialized @code{for-each-key} and +@code{for-each-elt} operations.@refill + +@defun collection? obj +A predicate, true initially of lists, vectors and strings. New sorts of +collections must answer @code{#t} to @code{collection?}.@refill +@end defun + +@deffn Procedure map-elts proc . collections +@deffnx Procedure do-elts proc . collections +@var{proc} is a procedure taking as many arguments as there are +@var{collections} (at least one). The @var{collections} are iterated +over in their natural order and @var{proc} is applied to the elements +yielded by each iteration in turn. The order in which the arguments are +supplied corresponds to te order in which the @var{collections} appear. +@code{do-elts} is used when only side-effects of @var{proc} are of +interest and its return value is unspecified. @code{map-elts} returns a +collection (actually a vector) of the results of the applications of +@var{proc}.@refill + +Example: +@lisp +(map-elts + (list 1 2 3) (vector 1 2 3)) + @result{} #(2 4 6) +@end lisp +@end deffn + +@deffn Procedure map-keys proc . collections +@deffnx Procedure do-keys proc . collections +These are analogous to @code{map-elts} and @code{do-elts}, but each +iteration is over the @var{collections}' @emph{keys} rather than their +elements.@refill + +Example: +@lisp +(map-keys + (list 1 2 3) (vector 1 2 3)) + @result{} #(0 2 4) +@end lisp +@end deffn + +@deffn Procedure for-each-key collection proc +@deffnx Procedure for-each-elt collection proc +These are like @code{do-keys} and @code{do-elts} but only for a single +collection; they are potentially more efficient. +@end deffn + +@defun reduce proc seed . collections +A generalization of the list-based @code{comlist:reduce-init} +(@xref{Lists as sequences}) to collections which will shadow the +list-based version if @code{(require 'collect)} follows +@ftindex collect +@code{(require 'common-list-functions)} (@xref{Common List Functions}).@refill +@ftindex common-list-functions + +Examples: +@lisp +(reduce + 0 (vector 1 2 3)) + @result{} 6 +(reduce union '() '((a b c) (b c d) (d a))) + @result{} (c b d a). +@end lisp +@end defun + +@defun any? pred . collections +A generalization of the list-based @code{some} (@xref{Lists as +sequences}) to collections.@refill + +Example: +@lisp +(any? odd? (list 2 3 4 5)) + @result{} #t +@end lisp +@end defun + +@defun every? pred . collections +A generalization of the list-based @code{every} (@xref{Lists as +sequences}) to collections.@refill + +Example: +@lisp +(every? collection? '((1 2) #(1 2))) + @result{} #t +@end lisp +@end defun + +@defun empty? collection +Returns @code{#t} iff there are no elements in @var{collection}. + +@code{(empty? @var{collection}) @equiv{} (zero? (size @var{collection}))} +@end defun + +@defun size collection +Returns the number of elements in @var{collection}. +@end defun + +@defun Setter list-ref +See @xref{Setters} for a definition of @dfn{setter}. N.B. +@code{(setter list-ref)} doesn't work properly for element 0 of a +list.@refill +@end defun + +Here is a sample collection: @code{simple-table} which is also a +@code{table}.@refill +@lisp +(define-predicate TABLE?) +(define-operation (LOOKUP table key failure-object)) +(define-operation (ASSOCIATE! table key value)) ;; returns key +(define-operation (REMOVE! table key)) ;; returns value + +(define (MAKE-SIMPLE-TABLE) + (let ( (table (list)) ) + (object + ;; table behaviors + ((TABLE? self) #t) + ((SIZE self) (size table)) + ((PRINT self port) (format port "#")) + ((LOOKUP self key failure-object) + (cond + ((assq key table) => cdr) + (else failure-object) + )) + ((ASSOCIATE! self key value) + (cond + ((assq key table) + => (lambda (bucket) (set-cdr! bucket value) key)) + (else + (set! table (cons (cons key value) table)) + key) + )) + ((REMOVE! self key);; returns old value + (cond + ((null? table) (slib:error "TABLE:REMOVE! Key not found: " key)) + ((eq? key (caar table)) + (let ( (value (cdar table)) ) + (set! table (cdr table)) + value) + ) + (else + (let loop ( (last table) (this (cdr table)) ) + (cond + ((null? this) + (slib:error "TABLE:REMOVE! Key not found: " key)) + ((eq? key (caar this)) + (let ( (value (cdar this)) ) + (set-cdr! last (cdr this)) + value) + ) + (else + (loop (cdr last) (cdr this))) + ) ) ) + )) + ;; collection behaviors + ((COLLECTION? self) #t) + ((GEN-KEYS self) (collect:list-gen-elts (map car table))) + ((GEN-ELTS self) (collect:list-gen-elts (map cdr table))) + ((FOR-EACH-KEY self proc) + (for-each (lambda (bucket) (proc (car bucket))) table) + ) + ((FOR-EACH-ELT self proc) + (for-each (lambda (bucket) (proc (cdr bucket))) table) + ) + ) ) ) +@end lisp -@subsubsection Configuration Variables -Format has some configuration variables at the beginning of -@file{format.scm} to suit the systems and users needs. There should be -no modification necessary for the configuration that comes with SLIB. -If modification is desired the variable should be set after the format -code is loaded. Format detects automatically if the running scheme -system implements floating point numbers and complex numbers. -@table @asis -@item @var{format:symbol-case-conv} -Symbols are converted by @code{symbol->string} so the case type of the -printed symbols is implementation dependent. -@code{format:symbol-case-conv} is a one arg closure which is either -@code{#f} (no conversion), @code{string-upcase}, @code{string-downcase} -or @code{string-capitalize}. (default @code{#f}) -@item @var{format:iobj-case-conv} -As @var{format:symbol-case-conv} but applies for the representation of -implementation internal objects. (default @code{#f}) +@node Dynamic Data Type, Hash Tables, Collections, Data Structures +@subsection Dynamic Data Type -@item @var{format:expch} -The character prefixing the exponent value in @code{~E} printing. (default -@code{#\E}) +@code{(require 'dynamic)} +@ftindex dynamic -@end table +@defun make-dynamic obj +Create and returns a new @dfn{dynamic} whose global value is @var{obj}. +@end defun -@subsubsection Compatibility With Other Format Implementations +@defun dynamic? obj +Returns true if and only if @var{obj} is a dynamic. No object +satisfying @code{dynamic?} satisfies any of the other standard type +predicates.@refill +@end defun -@table @asis -@item SLIB format 2.x: -See @file{format.doc}. +@defun dynamic-ref dyn +Return the value of the given dynamic in the current dynamic +environment. +@end defun -@item SLIB format 1.4: -Downward compatible except for padding support and @code{~A}, @code{~S}, -@code{~P}, @code{~X} uppercase printing. SLIB format 1.4 uses C-style -@code{printf} padding support which is completely replaced by the CL -@code{format} padding style. +@deffn Procedure dynamic-set! dyn obj +Change the value of the given dynamic to @var{obj} in the current +dynamic environment. The returned value is unspecified.@refill +@end deffn -@item MIT C-Scheme 7.1: -Downward compatible except for @code{~}, which is not documented -(ignores all characters inside the format string up to a newline -character). (7.1 implements @code{~a}, @code{~s}, -~@var{newline}, @code{~~}, @code{~%}, numerical and variable -parameters and @code{:/@@} modifiers in the CL sense).@refill +@defun call-with-dynamic-binding dyn obj thunk +Invoke and return the value of the given thunk in a new, nested dynamic +environment in which the given dynamic has been bound to a new location +whose initial contents are the value @var{obj}. This dynamic +environment has precisely the same extent as the invocation of the thunk +and is thus captured by continuations created within that invocation and +re-established by those continuations when they are invoked.@refill +@end defun -@item Elk 1.5/2.0: -Downward compatible except for @code{~A} and @code{~S} which print in -uppercase. (Elk implements @code{~a}, @code{~s}, @code{~~}, and -@code{~%} (no directive parameters or modifiers)).@refill +The @code{dynamic-bind} macro is not implemented. -@item Scheme->C 01nov91: -Downward compatible except for an optional destination parameter: S2C -accepts a format call without a destination which returns a formatted -string. This is equivalent to a #f destination in S2C. (S2C implements -@code{~a}, @code{~s}, @code{~c}, @code{~%}, and @code{~~} (no directive -parameters or modifiers)).@refill -@end table -This implementation of format is solely useful in the SLIB context -because it requires other components provided by SLIB.@refill +@node Hash Tables, Hashing, Dynamic Data Type, Data Structures +@subsection Hash Tables -@node Generic-Write, Line I/O, Format, Procedures -@section Generic-Write +@code{(require 'hash-table)} +@ftindex hash-table -@code{(require 'generic-write)} +@defun predicate->hash pred +Returns a hash function (like @code{hashq}, @code{hashv}, or +@code{hash}) corresponding to the equality predicate @var{pred}. +@var{pred} should be @code{eq?}, @code{eqv?}, @code{equal?}, @code{=}, +@code{char=?}, @code{char-ci=?}, @code{string=?}, or +@code{string-ci=?}.@refill +@end defun -@code{generic-write} is a procedure that transforms a Scheme data value -(or Scheme program expression) into its textual representation and -prints it. The interface to the procedure is sufficiently general to -easily implement other useful formatting procedures such as pretty -printing, output to a string and truncated output.@refill +A hash table is a vector of association lists. -@deffn Procedure generic-write obj display? width output -@table @var -@item obj -Scheme data value to transform. -@item display? -Boolean, controls whether characters and strings are quoted. -@item width -Extended boolean, selects format: -@table @asis -@item #f -single line format -@item integer > 0 -pretty-print (value = max nb of chars per line) -@end table -@item output -Procedure of 1 argument of string type, called repeatedly with -successive substrings of the textual representation. This procedure can -return @code{#f} to stop the transformation. -@end table +@defun make-hash-table k +Returns a vector of @var{k} empty (association) lists. +@end defun -The value returned by @code{generic-write} is undefined. +Hash table functions provide utilities for an associative database. +These functions take an equality predicate, @var{pred}, as an argument. +@var{pred} should be @code{eq?}, @code{eqv?}, @code{equal?}, @code{=}, +@code{char=?}, @code{char-ci=?}, @code{string=?}, or +@code{string-ci=?}.@refill -Examples: -@lisp -(write obj) @equiv{} (generic-write obj #f #f @var{display-string}) -(display obj) @equiv{} (generic-write obj #t #f @var{display-string}) -@end lisp -@noindent -where -@lisp -@var{display-string} @equiv{} -(lambda (s) (for-each write-char (string->list s)) #t) -@end lisp -@end deffn +@defun predicate->hash-asso pred +Returns a hash association function of 2 arguments, @var{key} and +@var{hashtab}, corresponding to @var{pred}. The returned function +returns a key-value pair whose key is @var{pred}-equal to its first +argument or @code{#f} if no key in @var{hashtab} is @var{pred}-equal to +the first argument.@refill +@end defun +@defun hash-inquirer pred +Returns a procedure of 3 arguments, @code{hashtab} and @code{key}, which +returns the value associated with @code{key} in @code{hashtab} or +@code{#f} if key does not appear in @code{hashtab}.@refill +@end defun +@defun hash-associator pred +Returns a procedure of 3 arguments, @var{hashtab}, @var{key}, and +@var{value}, which modifies @var{hashtab} so that @var{key} and +@var{value} associated. Any previous value associated with @var{key} +will be lost.@refill +@end defun +@defun hash-remover pred +Returns a procedure of 2 arguments, @var{hashtab} and @var{key}, which +modifies @var{hashtab} so that the association whose key is @var{key} is +removed.@refill +@end defun +@defun hash-map proc hash-table +Returns a new hash table formed by mapping @var{proc} over the +keys and values of @var{hash-table}. @var{proc} must be a function of 2 +arguments which returns the new value part. +@end defun -@node Line I/O, Multi-Processing, Generic-Write, Procedures -@section Line I/O +@defun hash-for-each proc hash-table +Applies @var{proc} to each pair of keys and values of @var{hash-table}. +@var{proc} must be a function of 2 arguments. The returned value is +unspecified. +@end defun -@code{(require 'line-i/o)} -@defun read-line -@defunx read-line port -Returns a string of the characters up to, but not including a newline or -end of file, updating @var{port} to point to the character following the -newline. If no characters are available, an end of file object is -returned. @var{port} may be omitted, in which case it defaults to the -value returned by @code{current-input-port}.@refill -@end defun -@defun read-line! string -@defunx read-line! string port -Fills @var{string} with characters up to, but not including a newline or -end of file, updating the port to point to the last character read or -following the newline if it was read. If no characters are available, -an end of file object is returned. If a newline or end of file was -found, the number of characters read is returned. Otherwise, @code{#f} -is returned. @var{port} may be omitted, in which case it defaults to -the value returned by @code{current-input-port}.@refill -@end defun -@defun write-line string -@defunx write-line string port -Writes @var{string} followed by a newline to the given port and returns -an unspecified value. Port may be omited, in which case it defaults to -the value returned by @code{current-input-port}.@refill -@end defun +@node Hashing, Priority Queues, Hash Tables, Data Structures +@subsection Hashing +@code{(require 'hash)} +@ftindex hash +These hashing functions are for use in quickly classifying objects. +Hash tables use these functions. -@node Multi-Processing, Object-To-String, Line I/O, Procedures -@section Multi-Processing +@defun hashq obj k +@defunx hashv obj k +@defunx hash obj k +Returns an exact non-negative integer less than @var{k}. For each +non-negative integer less than @var{k} there are arguments @var{obj} for +which the hashing functions applied to @var{obj} and @var{k} returns +that integer.@refill -@code{(require 'process)} +For @code{hashq}, @code{(eq? obj1 obj2)} implies @code{(= (hashq obj1 k) +(hashq obj2))}.@refill -@deffn Procedure add-process! proc -Adds proc, which must be a procedure (or continuation) capable of -accepting accepting one argument, to the @code{process:queue}. The -value returned is unspecified. The argument to @var{proc} should be -ignored. If @var{proc} returns, the process is killed.@refill -@end deffn +For @code{hashv}, @code{(eqv? obj1 obj2)} implies @code{(= (hashv obj1 k) +(hashv obj2))}.@refill -@deffn Procedure process:schedule! -Saves the current process on @code{process:queue} and runs the next -process from @code{process:queue}. The value returned is -unspecified.@refill -@end deffn +For @code{hash}, @code{(equal? obj1 obj2)} implies @code{(= (hash obj1 k) +(hash obj2))}.@refill + +@code{hash}, @code{hashv}, and @code{hashq} return in time bounded by a +constant. Notice that items having the same @code{hash} implies the +items have the same @code{hashv} implies the items have the same +@code{hashq}.@refill +@end defun -@deffn Procedure kill-process! -Kills the current process and runs the next process from -@code{process:queue}. If there are no more processes on -@code{process:queue}, @code{(slib:exit)} is called (@xref{System}). -@end deffn +@code{(require 'sierpinski)} +@ftindex sierpinski +@defun make-sierpinski-indexer max-coordinate +Returns a procedure (eg hash-function) of 2 numeric arguments which +preserves @emph{nearness} in its mapping from NxN to N. + +@var{max-coordinate} is the maximum coordinate (a positive integer) of a +population of points. The returned procedures is a function that takes +the x and y coordinates of a point, (non-negative integers) and returns +an integer corresponding to the relative position of that point along a +Sierpinski curve. (You can think of this as computing a (pseudo-) +inverse of the Sierpinski spacefilling curve.) +Example use: Make an indexer (hash-function) for integer points lying in +square of integer grid points [0,99]x[0,99]: +@example +(define space-key (make-sierpinski-indexer 100)) +@end example +Now let's compute the index of some points: +@example +(space-key 24 78) @result{} 9206 +(space-key 23 80) @result{} 9172 +@end example +Note that locations (24, 78) and (23, 80) are near in index and +therefore, because the Sierpinski spacefilling curve is continuous, we +know they must also be near in the plane. Nearness in the plane does +not, however, necessarily correspond to nearness in index, although it +@emph{tends} to be so. +Example applications: +@itemize @bullet -@node Object-To-String, Pretty-Print, Multi-Processing, Procedures -@section Object-To-String +@item +Sort points by Sierpinski index to get heuristic solution to +@emph{travelling salesman problem}. For details of performance, +see L. Platzman and J. Bartholdi, "Spacefilling curves and the +Euclidean travelling salesman problem", JACM 36(4):719--737 +(October 1989) and references therein. -@code{(require 'object->string)} +@item +Use Sierpinski index as key by which to store 2-dimensional data +in a 1-dimensional data structure (such as a table). Then +locations that are near each other in 2-d space will tend to +be near each other in 1-d data structure; and locations that +are near in 1-d data structure will be near in 2-d space. This +can significantly speed retrieval from secondary storage because +contiguous regions in the plane will tend to correspond to +contiguous regions in secondary storage. (This is a standard +technique for managing CAD/CAM or geographic data.) -@defun object->string obj -Returns the textual representation of @var{obj} as a string. +@end itemize @end defun +@code{(require 'soundex)} +@ftindex soundex -@node Pretty-Print, Sorting, Object-To-String, Procedures -@section Pretty-Print +@defun soundex name +Computes the @emph{soundex} hash of @var{name}. Returns a string of an +initial letter and up to three digits between 0 and 6. Soundex +supposedly has the property that names that sound similar in normal +English pronunciation tend to map to the same key. -@code{(require 'pretty-print)} +Soundex was a classic algorithm used for manual filing of personal +records before the advent of computers. It performs adequately for +English names but has trouble with other nationalities. -@deffn Procedure pretty-print obj -@deffnx Procedure pretty-print obj port +See Knuth, Vol. 3 @cite{Sorting and searching}, pp 391--2 -@code{pretty-print}s @var{obj} on @var{port}. If @var{port} is not -specified, @code{current-output-port} is used. +To manage unusual inputs, @code{soundex} omits all non-alphabetic +characters. Consequently, in this implementation: -Example: @example -@group -(pretty-print '((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) - (16 17 18 19 20) (21 22 23 24 25))) - @print{} ((1 2 3 4 5) - @print{} (6 7 8 9 10) - @print{} (11 12 13 14 15) - @print{} (16 17 18 19 20) - @print{} (21 22 23 24 25)) -@end group +(soundex ) @result{} "" +(soundex "") @result{} "" @end example -@end deffn +Examples from Knuth: -@code{(require 'pprint-file)} +@example +(map soundex '("Euler" "Gauss" "Hilbert" "Knuth" + "Lloyd" "Lukasiewicz")) + @result{} ("E460" "G200" "H416" "K530" "L300" "L222") -@deffn Procedure pprint-file infile -@deffnx Procedure pprint-file infile outfile -Pretty-prints all the code in @var{infile}. If @var{outfile} is -specified, the output goes to @var{outfile}, otherwise it goes to -@code{(current-output-port)}.@refill -@end deffn +(map soundex '("Ellery" "Ghosh" "Heilbronn" "Kant" + "Ladd" "Lissajous")) + @result{} ("E460" "G200" "H416" "K530" "L300" "L222") +@end example -@defun pprint-filter-file infile proc outfile -@defunx pprint-filter-file infile proc -@var{infile} is a port or a string naming an existing file. Scheme -source code expressions and definitions are read from the port (or file) -and @var{proc} is applied to them sequentially. +Some cases in which the algorithm fails (Knuth): -@var{outfile} is a port or a string. If no @var{outfile} is specified -then @code{current-output-port} is assumed. These expanded expressions -are then @code{pretty-print}ed to this port. +@example +(map soundex '("Rogers" "Rodgers")) @result{} ("R262" "R326") -Whitepsace and comments (introduced by @code{;}) which are not part of -scheme expressions are reproduced in the output. This procedure does -not affect the values returned by @code{current-input-port} and -@code{current-output-port}.@refill -@end defun +(map soundex '("Sinclair" "St. Clair")) @result{} ("S524" "S324") -@code{pprint-filter-file} can be used to pre-compile macro-expansion and -thus can reduce loading time. The following will write into -@file{exp-code.scm} the result of expanding all defmacros in -@file{code.scm}. -@lisp -(require 'pprint-file) -(require 'defmacroexpand) -(defmacro:load "my-macros.scm") -(pprint-filter-file "code.scm" defmacro:expand* "exp-code.scm") -@end lisp +(map soundex '("Tchebysheff" "Chebyshev")) @result{} ("T212" "C121") +@end example +@end defun -@node Sorting, Topological Sort, Pretty-Print, Procedures -@section Sorting +@node Priority Queues, Queues, Hashing, Data Structures +@subsection Priority Queues -@code{(require 'sort)} +@code{(require 'priority-queue)} +@ftindex priority-queue -Many Scheme systems provide some kind of sorting functions. They do -not, however, always provide the @emph{same} sorting functions, and -those that I have had the opportunity to test provided inefficient ones -(a common blunder is to use quicksort which does not perform well). +@defun make-heap pred}, @code{char?}, -@code{char-ci?}, @code{string?}, -@code{string-ci?} are suitable for use as -comparison functions. Think of @code{(less? x y)} as saying when -@code{x} must @emph{not} precede @code{y}.@refill +A @dfn{queue} is a list where elements can be added to both the front +and rear, and removed from the front (i.e., they are what are often +called @dfn{dequeues}). A queue may also be used like a stack.@refill -@defun sorted? sequence less? -Returns @code{#t} when the sequence argument is in non-decreasing order -according to @var{less?} (that is, there is no adjacent pair @code{@dots{} x -y @dots{}} for which @code{(less? y x)}).@refill +@defun make-queue +Returns a new, empty queue. +@end defun -Returns @code{#f} when the sequence contains at least one out-of-order -pair. It is an error if the sequence is neither a list nor a vector. +@defun queue? obj +Returns @code{#t} if @var{obj} is a queue. @end defun -@defun merge list1 list2 less? -This merges two lists, producing a completely new list as result. I -gave serious consideration to producing a Common-LISP-compatible -version. However, Common LISP's @code{sort} is our @code{sort!} (well, -in fact Common LISP's @code{stable-sort} is our @code{sort!}, merge sort -is @emph{fast} as well as stable!) so adapting CL code to Scheme takes a -bit of work anyway. I did, however, appeal to CL to determine the -@emph{order} of the arguments. +@defun queue-empty? q +Returns @code{#t} if the queue @var{q} is empty. @end defun -@deffn Procedure merge! list1 list2 less? -Merges two lists, re-using the pairs of @var{list1} and @var{list2} to -build the result. If the code is compiled, and @var{less?} constructs -no new pairs, no pairs at all will be allocated. The first pair of the -result will be either the first pair of @var{list1} or the first pair of -@var{list2}, but you can't predict which. +@deffn Procedure queue-push! q datum +Adds @var{datum} to the front of queue @var{q}. +@end deffn -The code of @code{merge} and @code{merge!} could have been quite a bit -simpler, but they have been coded to reduce the amount of work done per -iteration. (For example, we only have one @code{null?} test per -iteration.)@refill +@deffn Procedure enquque! q datum +Adds @var{datum} to the rear of queue @var{q}. @end deffn -@defun sort sequence less? -Accepts either a list or a vector, and returns a new sequence which is -sorted. The new sequence is the same type as the input. Always -@code{(sorted? (sort sequence less?) less?)}. The original sequence is -not altered in any way. The new sequence shares its @emph{elements} -with the old one; no elements are copied.@refill +All of the following functions raise an error if the queue @var{q} is +empty.@refill + +@defun queue-front q +Returns the datum at the front of the queue @var{q}. @end defun -@deffn Procedure sort! sequence less? -Returns its sorted result in the original boxes. If the original -sequence is a list, no new storage is allocated at all. If the original -sequence is a vector, the sorted elements are put back in the same -vector. +@defun queue-rear q +Returns the datum at the rear of the queue @var{q}. +@end defun -Some people have been confused about how to use @code{sort!}, thinking -that it doesn't return a value. It needs to be pointed out that -@lisp -(set! slist (sort! slist <)) -@end lisp -@noindent -is the proper usage, not -@lisp -(sort! slist <) -@end lisp +@deffn Prcoedure queue-pop! q +@deffnx Procedure dequeue! q +Both of these procedures remove and return the datum at the front of the +queue. @code{queue-pop!} is used to suggest that the queue is being +used like a stack.@refill @end deffn -Note that these functions do @emph{not} accept a CL-style @samp{:key} -argument. A simple device for obtaining the same expressiveness is to -define@refill -@lisp -(define (keyed less? key) - (lambda (x y) (less? (key x) (key y)))) -@end lisp -@noindent -and then, when you would have written -@lisp -(sort a-sequence #'my-less :key #'my-key) -@end lisp -@noindent -in Common LISP, just write -@lisp -(sort! a-sequence (keyed my-less? my-key)) -@end lisp -@noindent -in Scheme. -@node Topological Sort, Standard Formatted I/O, Sorting, Procedures -@section Topological Sort -@code{(require 'topological-sort)} or @code{(require 'tsort)} -@noindent -The algorithm is inspired by Cormen, Leiserson and Rivest (1990) -@cite{Introduction to Algorithms}, chapter 23. -@defun tsort dag pred -@defunx topological-sort dag pred -where -@table @var -@item dag -is a list of sublists. The car of each sublist is a vertex. The cdr is -the adjacency list of that vertex, i.e. a list of all vertices to which -there exists an edge from the car vertex. -@item pred -is one of @code{eq?}, @code{eqv?}, @code{equal?}, @code{=}, -@code{char=?}, @code{char-ci=?}, @code{string=?}, or @code{string-ci=?}. -@end table +@node Records, Structures, Queues, Data Structures +@subsection Records -Sort the directed acyclic graph @var{dag} so that for every edge from -vertex @var{u} to @var{v}, @var{u} will come before @var{v} in the -resulting list of vertices. +@code{(require 'record)} +@ftindex record -Time complexity: O (|V| + |E|) +The Record package provides a facility for user to define their own +record data types. -Example (from Cormen): -@quotation -Prof. Bumstead topologically sorts his clothing when getting -dressed. The first argument to `tsort' describes which -garments he needs to put on before others. (For example, -Prof Bumstead needs to put on his shirt before he puts on his -tie or his belt.) `tsort' gives the correct order of dressing: -@end quotation +@defun make-record-type type-name field-names +Returns a @dfn{record-type descriptor}, a value representing a new data +type disjoint from all others. The @var{type-name} argument must be a +string, but is only used for debugging purposes (such as the printed +representation of a record of the new type). The @var{field-names} +argument is a list of symbols naming the @dfn{fields} of a record of the +new type. It is an error if the list contains any duplicates. It is +unspecified how record-type descriptors are represented.@refill +@end defun -@example -(require 'tsort) -(tsort '((shirt tie belt) - (tie jacket) - (belt jacket) - (watch) - (pants shoes belt) - (undershorts pants shoes) - (socks shoes)) - eq?) -@result{} -(socks undershorts pants shoes watch shirt belt tie jacket) -@end example +@c @defun make-record-sub-type type-name field-names rtd +@c Returns a @dfn{record-type descriptor}, a value representing a new data +@c type, disjoint from all others. The @var{type-name} argument must be a +@c string. The @var{field-names} argument is a list of symbols naming the +@c additional @dfn{fields} to be appended to @var{field-names} of +@c @var{rtd}. It is an error if the combinded list contains any +@c duplicates.@refill +@c +@c Record-modifiers and record-accessors for @var{rtd} work for the new +@c record-sub-type as well. But record-modifiers and record-accessors for +@c the new record-sub-type will not neccessarily work for @var{rtd}.@refill +@c @end defun + +@defun record-constructor rtd [field-names] +Returns a procedure for constructing new members of the type represented +by @var{rtd}. The returned procedure accepts exactly as many arguments +as there are symbols in the given list, @var{field-names}; these are +used, in order, as the initial values of those fields in a new record, +which is returned by the constructor procedure. The values of any +fields not named in that list are unspecified. The @var{field-names} +argument defaults to the list of field names in the call to +@code{make-record-type} that created the type represented by @var{rtd}; +if the @var{field-names} argument is provided, it is an error if it +contains any duplicates or any symbols not in the default list.@refill @end defun -@node Standard Formatted I/O, String-Case, Topological Sort, Procedures -@section Standard Formatted I/O +@defun record-predicate rtd +Returns a procedure for testing membership in the type represented by +@var{rtd}. The returned procedure accepts exactly one argument and +returns a true value if the argument is a member of the indicated record +type; it returns a false value otherwise.@refill +@end defun -@menu -* Standard Formatted Output:: -* Standard Formatted Input:: -@end menu +@c @defun record-sub-predicate rtd +@c Returns a procedure for testing membership in the type represented by +@c @var{rtd} or its parents. The returned procedure accepts exactly one +@c argument and returns a true value if the argument is a member of the +@c indicated record type or its parents; it returns a false value +@c otherwise.@refill +@c @end defun -@subsection stdio +@defun record-accessor rtd field-name +Returns a procedure for reading the value of a particular field of a +member of the type represented by @var{rtd}. The returned procedure +accepts exactly one argument which must be a record of the appropriate +type; it returns the current value of the field named by the symbol +@var{field-name} in that record. The symbol @var{field-name} must be a +member of the list of field-names in the call to @code{make-record-type} +that created the type represented by @var{rtd}.@refill +@end defun -@code{(require 'stdio)} -@code{require}s @code{printf} and @code{scanf} and additionally defines -the symbols: +@defun record-modifier rtd field-name +Returns a procedure for writing the value of a particular field of a +member of the type represented by @var{rtd}. The returned procedure +accepts exactly two arguments: first, a record of the appropriate type, +and second, an arbitrary Scheme value; it modifies the field named by +the symbol @var{field-name} in that record to contain the given value. +The returned value of the modifier procedure is unspecified. The symbol +@var{field-name} must be a member of the list of field-names in the call +to @code{make-record-type} that created the type represented by +@var{rtd}.@refill +@end defun -@defvar stdin -Defined to be @code{(current-input-port)}. -@end defvar -@defvar stdout -Defined to be @code{(current-output-port)}. -@end defvar -@defvar stderr -Defined to be @code{(current-error-port)}. -@end defvar +In May of 1996, as a product of discussion on the @code{rrrs-authors} +mailing list, I rewrote @file{record.scm} to portably implement type +disjointness for record data types. +As long as an implementation's procedures are opaque and the +@code{record} code is loaded before other programs, this will give +disjoint record types which are unforgeable and incorruptible by R4RS +procedures. -@node Standard Formatted Output, Standard Formatted Input, Standard Formatted I/O, Standard Formatted I/O -@subsection Standard Formatted Output +As a consequence, the procedures @code{record?}, +@code{record-type-descriptor}, @code{record-type-name}.and +@code{record-type-field-names} are no longer supported. -@code{(require 'printf)} +@ignore +@defun record? obj +Returns a true value if @var{obj} is a record of any type and a false +value otherwise. Note that @code{record?} may be true of any Scheme +value; of course, if it returns true for some particular value, then +@code{record-type-descriptor} is applicable to that value and returns an +appropriate descriptor.@refill +@end defun -@deffn Procedure printf format arg1 @dots{} -@deffnx Procedure fprintf port format arg1 @dots{} -@deffnx Procedure sprintf str format arg1 @dots{} +@defun record-type-descriptor record +Returns a record-type descriptor representing the type of the given +record. That is, for example, if the returned descriptor were passed to +@code{record-predicate}, the resulting predicate would return a true +value when passed the given record. Note that it is not necessarily the +case that the returned descriptor is the one that was passed to +@code{record-constructor} in the call that created the constructor +procedure that created the given record.@refill +@end defun -Each function converts, formats, and outputs its @var{arg1} @dots{} -arguments according to the control string @var{format} argument and -returns the number of characters output. +@defun record-type-name rtd +Returns the type-name associated with the type represented by rtd. The +returned value is @code{eqv?} to the @var{type-name} argument given in +the call to @code{make-record-type} that created the type represented by +@var{rtd}.@refill +@end defun -@code{printf} sends its output to the port @code{(current-output-port)}. -@code{fprintf} sends its output to the port @var{port}. @code{sprintf} -@code{string-set!}s locations of the non-constant string argument -@var{str} to the output characters. +@defun record-type-field-names rtd +Returns a list of the symbols naming the fields in members of the type +represented by @var{rtd}. The returned value is @code{equal?} to the +field-names argument given in the call to @code{make-record-type} that +created the type represented by @var{rtd}.@refill +@end defun +@end ignore -@quotation -@emph{Note:} sprintf should be changed to a macro so a @code{substring} -expression could be used for the @var{str} argument. -@end quotation -The string @var{format} contains plain characters which are copied to -the output stream, and conversion specifications, each of which results -in fetching zero or more of the arguments @var{arg1} @dots{}. The -results are undefined if there are an insufficient number of arguments -for the format. If @var{format} is exhausted while some of the -@var{arg1} @dots{} arguments remain unused, the excess @var{arg1} -@dots{} arguments are ignored. +@node Structures, , Records, Data Structures +@subsection Structures + +@code{(require 'struct)} (uses defmacros) +@ftindex struct + +@code{defmacro}s which implement @dfn{records} from the book +@cite{Essentials of Programming Languages} by Daniel P. Friedman, M. +Wand and C.T. Haynes. Copyright 1992 Jeff Alexander, Shinnder Lee, and +Lewis Patterson@refill + +Matthew McDonald added field setters. + +@defmac define-record tag (var1 var2 @dots{}) +Defines several functions pertaining to record-name @var{tag}: + +@defun make-@var{tag} var1 var2 @dots{} +@end defun +@defun @var{tag}? obj +@end defun +@defun @var{tag}->var1 obj +@end defun +@defun @var{tag}->var2 obj +@end defun +@dots{} +@defun set-@var{tag}-var1! obj val +@end defun +@defun set-@var{tag}-var2! obj val +@end defun +@dots{} + +Here is an example of its use. + +@example +(define-record term (operator left right)) +@result{} # +(define foo (make-term 'plus 1 2)) +@result{} foo +(term->left foo) +@result{} 1 +(set-term-left! foo 2345) +@result{} # +(term->left foo) +@result{} 2345 +@end example +@end defmac -The conversion specifications in a format string have the form: +@defmac variant-case exp (tag (var1 var2 @dots{}) body) @dots{} +executes the following for the matching clause: @example -% @r{[} @var{flags} @r{]} @r{[} @var{width} @r{]} @r{[} . @var{precision} @r{]} @r{[} @var{type} @r{]} @var{conversion} +((lambda (@var{var1} @var{var} @dots{}) @var{body}) + (@var{tag->var1} @var{exp}) + (@var{tag->var2} @var{exp}) @dots{}) @end example +@end defmac -An output conversion specifications consist of an initial @samp{%} -character followed in sequence by: -@itemize @bullet -@item -Zero or more @dfn{flag characters} that modify the normal behavior of -the conversion specification. +@node Procedures, Standards Support, Data Structures, Other Packages +@section Procedures -@table @asis -@item @samp{-} -Left-justify the result in the field. Normally the result is -right-justified. +Anything that doesn't fall neatly into any of the other categories winds +up here. -@item @samp{+} -For the signed @samp{%d} and @samp{%i} conversions and all inexact -conversions, prefix a plus sign if the value is positive. +@menu +* Common List Functions:: 'common-list-functions +* Tree Operations:: 'tree +* Chapter Ordering:: 'chapter-order +* Sorting:: 'sort +* Topological Sort:: Keep your socks on. +* String-Case:: 'string-case +* String Ports:: 'string-port +* String Search:: Also Search from a Port. +* Line I/O:: 'line-i/o +* Multi-Processing:: 'process +@end menu -@item @samp{ } -For the signed @samp{%d} and @samp{%i} conversions, if the result -doesn't start with a plus or minus sign, prefix it with a space -character instead. Since the @samp{+} flag ensures that the result -includes a sign, this flag is ignored if both are specified. -@item @samp{#} -For inexact conversions, @samp{#} specifies that the result should -always include a decimal point, even if no digits follow it. For the -@samp{%g} and @samp{%G} conversions, this also forces trailing zeros -after the decimal point to be printed where they would otherwise be -elided. +@node Common List Functions, Tree Operations, Procedures, Procedures +@subsection Common List Functions -For the @samp{%o} conversion, force the leading digit to be @samp{0}, as -if by increasing the precision. For @samp{%x} or @samp{%X}, prefix a -leading @samp{0x} or @samp{0X} (respectively) to the result. This -doesn't do anything useful for the @samp{%d}, @samp{%i}, or @samp{%u} -conversions. Using this flag produces output which can be parsed by the -@code{scanf} functions with the @samp{%i} conversion (@pxref{Standard -Formatted Input}). +@code{(require 'common-list-functions)} +@ftindex common-list-functions +The procedures below follow the Common LISP equivalents apart from +optional arguments in some cases. -@item @samp{0} -Pad the field with zeros instead of spaces. The zeros are placed after -any indication of sign or base. This flag is ignored if the @samp{-} -flag is also specified, or if a precision is specified for an exact -converson. -@end table +@menu +* List construction:: +* Lists as sets:: +* Lists as sequences:: +* Destructive list operations:: +* Non-List functions:: +@end menu -@item -An optional decimal integer specifying the @dfn{minimum field width}. -If the normal conversion produces fewer characters than this, the field -is padded (with spaces or zeros per the @samp{0} flag) to the specified -width. This is a @emph{minimum} width; if the normal conversion -produces more characters than this, the field is @emph{not} truncated. -@cindex minimum field width (@code{printf}) -Alternatively, if the field width is @samp{*}, the next argument in the -argument list (before the actual value to be printed) is used as the -field width. The width value must be an integer. If the value is -negative it is as though the @samp{-} flag is set (see above) and the -absolute value is used as the field width. +@node List construction, Lists as sets, Common List Functions, Common List Functions +@subsubsection List construction -@item -An optional @dfn{precision} to specify the number of digits to be -written for numeric conversions and the maximum field width for string -conversions. The precision is specified by a period (@samp{.}) followed -optionally by a decimal integer (which defaults to zero if omitted). -@cindex precision (@code{printf}) +@defun make-list k . init +@code{make-list} creates and returns a list of @var{k} elements. If +@var{init} is included, all elements in the list are initialized to +@var{init}.@refill -Alternatively, if the precision is @samp{.*}, the next argument in the -argument list (before the actual value to be printed) is used as the -precision. The value must be an integer, and is ignored if negative. -If you specify @samp{*} for both the field width and precision, the -field width argument precedes the precision argument. The @samp{.*} -precision is an enhancement. C library versions may not accept this -syntax. +Example: +@lisp +(make-list 3) + @result{} (# # #) +(make-list 5 'foo) + @result{} (foo foo foo foo foo) +@end lisp +@end defun -For the @samp{%f}, @samp{%e}, and @samp{%E} conversions, the precision -specifies how many digits follow the decimal-point character. The -default precision is @code{6}. If the precision is explicitly @code{0}, -the decimal point character is suppressed. -For the @samp{%g} and @samp{%G} conversions, the precision specifies how -many significant digits to print. Significant digits are the first -digit before the decimal point, and all the digits after it. If the -precision is @code{0} or not specified for @samp{%g} or @samp{%G}, it is -treated like a value of @code{1}. If the value being printed cannot be -expressed accurately in the specified number of digits, the value is -rounded to the nearest number that fits. +@defun list* x . y +Works like @code{list} except that the cdr of the last pair is the last +argument unless there is only one argument, when the result is just that +argument. Sometimes called @code{cons*}. E.g.:@refill +@lisp +(list* 1) + @result{} 1 +(list* 1 2 3) + @result{} (1 2 . 3) +(list* 1 2 '(3 4)) + @result{} (1 2 3 4) +(list* @var{args} '()) + @equiv{} (list @var{args}) +@end lisp +@end defun -For exact conversions, if a precision is supplied it specifies the -minimum number of digits to appear; leading zeros are produced if -necessary. If a precision is not supplied, the number is printed with -as many digits as necessary. Converting an exact @samp{0} with an -explicit precision of zero produces no characters. +@defun copy-list lst +@code{copy-list} makes a copy of @var{lst} using new pairs and returns +it. Only the top level of the list is copied, i.e., pairs forming +elements of the copied list remain @code{eq?} to the corresponding +elements of the original; the copy is, however, not @code{eq?} to the +original, but is @code{equal?} to it.@refill -@item -An optional one of @samp{l}, @samp{h} or @samp{L}, which is ignored for -numeric conversions. It is an error to specify these modifiers for -non-numeric conversions. +Example: +@lisp +(copy-list '(foo foo foo)) + @result{} (foo foo foo) +(define q '(foo bar baz bang)) +(define p q) +(eq? p q) + @result{} #t +(define r (copy-list q)) +(eq? q r) + @result{} #f +(equal? q r) + @result{} #t +(define bar '(bar)) +(eq? bar (car (copy-list (list bar 'foo)))) +@result{} #t + @end lisp +@end defun -@item -A character that specifies the conversion to be applied. -@end itemize -@subsubsection Exact Conversions -@table @asis -@item @samp{d}, @samp{i} -Print an integer as a signed decimal number. @samp{%d} and @samp{%i} -are synonymous for output, but are different when used with @code{scanf} -for input (@pxref{Standard Formatted Input}). -@item @samp{o} -Print an integer as an unsigned octal number. -@item @samp{u} -Print an integer as an unsigned decimal number. -@item @samp{x}, @samp{X} -Print an integer as an unsigned hexadecimal number. @samp{%x} prints -using the digits @samp{0123456789abcdef}. @samp{%X} prints using the -digits @samp{0123456789ABCDEF}. -@end table +@node Lists as sets, Lists as sequences, List construction, Common List Functions +@subsubsection Lists as sets -@subsubsection Inexact Conversions -@emph{Note:} Inexact conversions are not supported yet. +@code{eq?} is used to test for membership by all the procedures below +which treat lists as sets.@refill -@table @asis -@item @samp{f} -Print a floating-point number in fixed-point notation. +@defun adjoin e l +@code{adjoin} returns the adjoint of the element @var{e} and the list +@var{l}. That is, if @var{e} is in @var{l}, @code{adjoin} returns +@var{l}, otherwise, it returns @code{(cons @var{e} @var{l})}.@refill -@item @samp{e}, @samp{E} -Print a floating-point number in exponential notation. @samp{%e} prints -@samp{e} between mantissa and exponont. @samp{%E} prints @samp{E} -between mantissa and exponont. +Example: +@lisp +(adjoin 'baz '(bar baz bang)) + @result{} (bar baz bang) +(adjoin 'foo '(bar baz bang)) + @result{} (foo bar baz bang) +@end lisp +@end defun -@item @samp{g}, @samp{G} -Print a floating-point number in either normal or exponential notation, -whichever is more appropriate for its magnitude. @samp{%g} prints -@samp{e} between mantissa and exponont. @samp{%G} prints @samp{E} -between mantissa and exponont. -@end table +@defun union l1 l2 +@code{union} returns the combination of @var{l1} and @var{l2}. +Duplicates between @var{l1} and @var{l2} are culled. Duplicates within +@var{l1} or within @var{l2} may or may not be removed.@refill -@subsubsection Other Conversions -@table @asis -@item @samp{c} -Print a single character. The @samp{-} flag is the only one which can -be specified. It is an error to specify a precision. +Example: +@lisp +(union '(1 2 3 4) '(5 6 7 8)) + @result{} (4 3 2 1 5 6 7 8) +(union '(1 2 3 4) '(3 4 5 6)) + @result{} (2 1 3 4 5 6) +@end lisp +@end defun -@item @samp{s} -Print a string. The @samp{-} flag is the only one which can be -specified. A precision specifies the maximum number of characters to -output; otherwise all characters in the string are output. +@defun intersection l1 l2 +@code{intersection} returns all elements that are in both @var{l1} and +@var{l2}.@refill -@item @samp{a}, @samp{A} -Print a scheme expression. The @samp{-} flag left-justifies the output. -The @samp{#} flag specifies that strings and characters should be quoted -as by @code{write} (which can be read using @code{read}); otherwise, -output is as @code{display} prints. A precision specifies the maximum -number of characters to output; otherwise as many characters as needed -are output. +Example: +@lisp +(intersection '(1 2 3 4) '(3 4 5 6)) + @result{} (3 4) +(intersection '(1 2 3 4) '(5 6 7 8)) + @result{} () +@end lisp +@end defun -@emph{Note:} @samp{%a} and @samp{%A} are SLIB extensions. +@defun set-difference l1 l2 +@code{set-difference} returns the union of all elements that are in +@var{l1} but not in @var{l2}.@refill -@c @item @samp{p} -@c Print the value of a pointer. +Example: +@lisp +(set-difference '(1 2 3 4) '(3 4 5 6)) + @result{} (1 2) +(set-difference '(1 2 3 4) '(1 2 3 4 5 6)) + @result{} () +@end lisp +@end defun -@c @item @samp{n} -@c Get the number of characters printed so far. @xref{Other Output Conversions}. -@c Note that this conversion specification never produces any output. +@defun member-if pred lst +@code{member-if} returns @var{lst} if @code{(@var{pred} @var{element})} +is @code{#t} for any @var{element} in @var{lst}. Returns @code{#f} if +@var{pred} does not apply to any @var{element} in @var{lst}.@refill -@c @item @samp{m} -@c Print the string corresponding to the value of @code{errno}. -@c (This is a GNU extension.) -@c @xref{Other Output Conversions}. +Example: +@lisp +(member-if vector? '(1 2 3 4)) + @result{} #f +(member-if number? '(1 2 3 4)) + @result{} (1 2 3 4) +@end lisp +@end defun -@item @samp{%} -Print a literal @samp{%} character. No argument is consumed. It is an -error to specifiy flags, field width, precision, or type modifiers with -@samp{%%}. -@end table -@end deffn +@defun some pred lst . more-lsts +@var{pred} is a boolean function of as many arguments as there are list +arguments to @code{some} i.e., @var{lst} plus any optional arguments. +@var{pred} is applied to successive elements of the list arguments in +order. @code{some} returns @code{#t} as soon as one of these +applications returns @code{#t}, and is @code{#f} if none returns +@code{#t}. All the lists should have the same length.@refill -@node Standard Formatted Input, , Standard Formatted Output, Standard Formatted I/O -@subsection Standard Formatted Input +Example: +@lisp +(some odd? '(1 2 3 4)) + @result{} #t -@code{(require 'scanf)} +(some odd? '(2 4 6 8)) + @result{} #f -@deffn Function scanf-read-list format -@deffnx Function scanf-read-list format port -@deffnx Function scanf-read-list format string -@end deffn +(some > '(2 3) '(1 4)) + @result{} #f +@end lisp +@end defun -@defmac scanf format arg1 @dots{} -@defmacx fscanf port format arg1 @dots{} -@defmacx sscanf str format arg1 @dots{} +@defun every pred lst . more-lsts +@code{every} is analogous to @code{some} except it returns @code{#t} if +every application of @var{pred} is @code{#t} and @code{#f} +otherwise.@refill -Each function reads characters, interpreting them according to the -control string @var{format} argument. +Example: +@lisp +(every even? '(1 2 3 4)) + @result{} #f -@code{scanf-read-list} returns a list of the items specified as far as -the input matches @var{format}. @code{scanf}, @code{fscanf}, and -@code{sscanf} return the number of items successfully matched and -stored. @code{scanf}, @code{fscanf}, and @code{sscanf} also set the -location corresponding to @var{arg1} @dots{} using the methods: +(every even? '(2 4 6 8)) + @result{} #t -@table @asis -@item symbol -@code{set!} -@item car expression -@code{set-car!} -@item cdr expression -@code{set-cdr!} -@item vector-ref expression -@code{vector-set!} -@item substring expression -@code{substring-move-left!} -@end table +(every > '(2 3) '(1 4)) + @result{} #f +@end lisp +@end defun -The argument to a @code{substring} expression in @var{arg1} @dots{} must -be a non-constant string. Characters will be stored starting at the -position specified by the second argument to @code{substring}. The -number of characters stored will be limited by either the position -specified by the third argument to @code{substring} or the length of the -matched string, whichever is less. +@defun notany pred . lst +@code{notany} is analogous to @code{some} but returns @code{#t} if no +application of @var{pred} returns @code{#t} or @code{#f} as soon as any +one does.@refill +@end defun -The control string, @var{format}, contains conversion specifications and -other characters used to direct interpretation of input sequences. The -control string contains: +@defun notevery pred . lst +@code{notevery} is analogous to @code{some} but returns @code{#t} as soon +as an application of @var{pred} returns @code{#f}, and @code{#f} +otherwise.@refill -@itemize @bullet -@item White-space characters (blanks, tabs, newlines, or formfeeds) -that cause input to be read (and discarded) up to the next -non-white-space character. +Example: +@lisp +(notevery even? '(1 2 3 4)) + @result{} #t -@item An ordinary character (not @samp{%}) that must match the next -character of the input stream. +(notevery even? '(2 4 6 8)) + @result{} #f +@end lisp +@end defun -@item Conversion specifications, consisting of the character @samp{%}, an -optional assignment suppressing character @samp{*}, an optional -numerical maximum-field width, an optional @samp{l}, @samp{h} or -@samp{L} which is ignored, and a conversion code. +@defun find-if pred lst +@code{find-if} searches for the first @var{element} in @var{lst} such +that @code{(@var{pred} @var{element})} returns @code{#t}. If it finds +any such @var{element} in @var{lst}, @var{element} is returned. +Otherwise, @code{#f} is returned.@refill -@c @item The conversion specification can alternatively be prefixed by -@c the character sequence @samp{%n$} instead of the character @samp{%}, -@c where @var{n} is a decimal integer in the range. The @samp{%n$} -@c construction indicates that the value of the next input field should be -@c placed in the @var{n}th place in the return list, rather than to the next -@c unused one. The two forms of introducing a conversion specification, -@c @samp{%} and @samp{%n$}, must not be mixed within a single format string -@c with the following exception: Skip fields (see below) can be designated -@c as @samp{%*} or @samp{%n$*}. In the latter case, @var{n} is ignored. +Example: +@lisp +(find-if number? '(foo 1 bar 2)) + @result{} 1 -@end itemize +(find-if number? '(foo bar baz bang)) + @result{} #f -Unless the specification contains the @samp{n} conversion character -(described below), a conversion specification directs the conversion of -the next input field. The result of a conversion specification is -returned in the position of the corresponding argument points, unless -@samp{*} indicates assignment suppression. Assignment suppression -provides a way to describe an input field to be skipped. An input field -is defined as a string of characters; it extends to the next -inappropriate character or until the field width, if specified, is -exhausted. +(find-if symbol? '(1 2 foo bar)) + @result{} foo +@end lisp +@end defun -@quotation -@emph{Note:} This specification of format strings differs from the -@cite{ANSI C} and @cite{POSIX} specifications. In SLIB, white space -before an input field is not skipped unless white space appears before -the conversion specification in the format string. In order to write -format strings which work identically with @cite{ANSI C} and SLIB, -prepend whitespace to all conversion specifications except @samp{[} and -@samp{c}. -@end quotation +@defun remove elt lst +@code{remove} removes all occurrences of @var{elt} from @var{lst} using +@code{eqv?} to test for equality and returns everything that's left. +N.B.: other implementations (Chez, Scheme->C and T, at least) use +@code{equal?} as the equality test.@refill -The conversion code indicates the interpretation of the input field; For -a suppressed field, no value is returned. The following conversion -codes are legal: +Example: +@lisp +(remove 1 '(1 2 1 3 1 4 1 5)) + @result{} (2 3 4 5) -@table @asis +(remove 'foo '(bar baz bang)) + @result{} (bar baz bang) +@end lisp +@end defun -@item @samp{%} -A single % is expected in the input at this point; no value is returned. +@defun remove-if pred lst +@code{remove-if} removes all @var{element}s from @var{lst} where +@code{(@var{pred} @var{element})} is @code{#t} and returns everything +that's left.@refill -@item @samp{d}, @samp{D} -A decimal integer is expected. +Example: +@lisp +(remove-if number? '(1 2 3 4)) + @result{} () -@item @samp{u}, @samp{U} -An unsigned decimal integer is expected. +(remove-if even? '(1 2 3 4 5 6 7 8)) + @result{} (1 3 5 7) +@end lisp +@end defun -@item @samp{o}, @samp{O} -An octal integer is expected. +@defun remove-if-not pred lst +@code{remove-if-not} removes all @var{element}s from @var{lst} for which +@code{(@var{pred} @var{element})} is @code{#f} and returns everything that's +left.@refill -@item @samp{x}, @samp{X} -A hexadecimal integer is expected. +Example: +@lisp +(remove-if-not number? '(foo bar baz)) + @result{} () +(remove-if-not odd? '(1 2 3 4 5 6 7 8)) + @result{} (1 3 5 7) +@end lisp +@end defun -@item @samp{i} -An integer is expected. Returns the value of the next input item, -interpreted according to C conventions; a leading @samp{0} implies -octal, a leading @samp{0x} implies hexadecimal; otherwise, decimal is -assumed. +@defun has-duplicates? lst +returns @code{#t} if 2 members of @var{lst} are @code{equal?}, @code{#f} +otherwise. +Example: +@lisp +(has-duplicates? '(1 2 3 4)) + @result{} #f -@item @samp{n} -Returns the total number of bytes (including white space) read by -@code{scanf}. No input is consumed by @code{%n}. +(has-duplicates? '(2 4 3 4)) + @result{} #t +@end lisp +@end defun -@item @samp{f}, @samp{F}, @samp{e}, @samp{E}, @samp{g}, @samp{G} -A floating-point number is expected. The input format for -floating-point numbers is an optionally signed string of digits, -possibly containing a radix character @samp{.}, followed by an optional -exponent field consisting of an @samp{E} or an @samp{e}, followed by an -optional @samp{+}, @samp{-}, or space, followed by an integer. -@item @samp{c}, @samp{C} -@var{Width} characters are expected. The normal skip-over-white-space -is suppressed in this case; to read the next non-space character, use -@samp{%1s}. If a field width is given, a string is returned; up to the -indicated number of characters is read. +@node Lists as sequences, Destructive list operations, Lists as sets, Common List Functions +@subsubsection Lists as sequences + +@defun position obj lst +@code{position} returns the 0-based position of @var{obj} in @var{lst}, +or @code{#f} if @var{obj} does not occur in @var{lst}.@refill -@item @samp{s}, @samp{S} -A character string is expected The input field is terminated by a -white-space character. @code{scanf} cannot read a null string. +Example: +@lisp +(position 'foo '(foo bar baz bang)) + @result{} 0 +(position 'baz '(foo bar baz bang)) + @result{} 2 +(position 'oops '(foo bar baz bang)) + @result{} #f +@end lisp +@end defun -@item @samp{[} -Indicates string data and the normal skip-over-leading-white-space is -suppressed. The left bracket is followed by a set of characters, called -the scanset, and a right bracket; the input field is the maximal -sequence of input characters consisting entirely of characters in the -scanset. @samp{^}, when it appears as the first character in the -scanset, serves as a complement operator and redefines the scanset as -the set of all characters not contained in the remainder of the scanset -string. Construction of the scanset follows certain conventions. A -range of characters may be represented by the construct first-last, -enabling @samp{[0123456789]} to be expressed @samp{[0-9]}. Using this -convention, first must be lexically less than or equal to last; -otherwise, the dash stands for itself. The dash also stands for itself -when it is the first or the last character in the scanset. To include -the right square bracket as an element of the scanset, it must appear as -the first character (possibly preceded by a @samp{^}) of the scanset, in -which case it will not be interpreted syntactically as the closing -bracket. At least one character must match for this conversion to -succeed. -@end table +@defun reduce p lst +@code{reduce} combines all the elements of a sequence using a binary +operation (the combination is left-associative). For example, using +@code{+}, one can add up all the elements. @code{reduce} allows you to +apply a function which accepts only two arguments to more than 2 +objects. Functional programmers usually refer to this as @dfn{foldl}. +@code{collect:reduce} (@xref{Collections}) provides a version of +@code{collect} generalized to collections.@refill -The @code{scanf} functions terminate their conversions at end-of-file, -at the end of the control string, or when an input character conflicts -with the control string. In the latter case, the offending character is -left unread in the input stream. -@end defmac +Example: +@lisp +(reduce + '(1 2 3 4)) + @result{} 10 +(define (bad-sum . l) (reduce + l)) +(bad-sum 1 2 3 4) + @equiv{} (reduce + (1 2 3 4)) + @equiv{} (+ (+ (+ 1 2) 3) 4) +@result{} 10 +(bad-sum) + @equiv{} (reduce + ()) + @result{} () +(reduce string-append '("hello" "cruel" "world")) + @equiv{} (string-append (string-append "hello" "cruel") "world") + @result{} "hellocruelworld" +(reduce anything '()) + @result{} () +(reduce anything '(x)) + @result{} x +@end lisp -@node String-Case, String Ports, Standard Formatted I/O, Procedures -@section String-Case +What follows is a rather non-standard implementation of @code{reverse} +in terms of @code{reduce} and a combinator elsewhere called +@dfn{C}.@refill -@code{(require 'string-case)} +@lisp +;;; Contributed by Jussi Piitulainen (jpiitula@@ling.helsinki.fi) -@deffn Procedure string-upcase str -@deffnx Procedure string-downcase str -@deffnx Procedure string-capitalize str -The obvious string conversion routines. These are non-destructive. -@end deffn +(define commute + (lambda (f) + (lambda (x y) + (f y x)))) -@defun string-upcase! str -@defunx string-downcase! str -@defunx string-captialize! str -The destructive versions of the functions above. +(define reverse + (lambda (args) + (reduce-init (commute cons) '() args))) +@end lisp @end defun +@defun reduce-init p init lst +@code{reduce-init} is the same as reduce, except that it implicitly +inserts @var{init} at the start of the list. @code{reduce-init} is +preferred if you want to handle the null list, the one-element, and +lists with two or more elements consistently. It is common to use the +operator's idempotent as the initializer. Functional programmers +usually call this @dfn{foldl}.@refill +Example: +@lisp +(define (sum . l) (reduce-init + 0 l)) +(sum 1 2 3 4) + @equiv{} (reduce-init + 0 (1 2 3 4)) + @equiv{} (+ (+ (+ (+ 0 1) 2) 3) 4) + @result{} 10 +(sum) + @equiv{} (reduce-init + 0 '()) + @result{} 0 +(reduce-init string-append "@@" '("hello" "cruel" "world")) +@equiv{} +(string-append (string-append (string-append "@@" "hello") + "cruel") + "world") +@result{} "@@hellocruelworld" +@end lisp +Given a differentiation of 2 arguments, @code{diff}, the following will +differentiate by any number of variables. +@lisp +(define (diff* exp . vars) + (reduce-init diff exp vars)) +@end lisp -@node String Ports, String Search, String-Case, Procedures -@section String Ports +Example: +@lisp +;;; Real-world example: Insertion sort using reduce-init. -@code{(require 'string-port)} +(define (insert l item) + (if (null? l) + (list item) + (if (< (car l) item) + (cons (car l) (insert (cdr l) item)) + (cons item l)))) +(define (insertion-sort l) (reduce-init insert '() l)) -@deffn Procedure call-with-output-string proc -@var{proc} must be a procedure of one argument. This procedure calls -@var{proc} with one argument: a (newly created) output port. When the -function returns, the string composed of the characters written into the -port is returned.@refill -@end deffn +(insertion-sort '(3 1 4 1 5) + @equiv{} (reduce-init insert () (3 1 4 1 5)) + @equiv{} (insert (insert (insert (insert (insert () 3) 1) 4) 1) 5) + @equiv{} (insert (insert (insert (insert (3)) 1) 4) 1) 5) + @equiv{} (insert (insert (insert (1 3) 4) 1) 5) + @equiv{} (insert (insert (1 3 4) 1) 5) + @equiv{} (insert (1 1 3 4) 5) + @result{} (1 1 3 4 5) + @end lisp +@end defun -@deffn Procedure call-with-input-string string proc -@var{proc} must be a procedure of one argument. This procedure calls -@var{proc} with one argument: an (newly created) input port from which -@var{string}'s contents may be read. When @var{proc} returns, the port -is closed and the value yielded by the procedure @var{proc} is -returned.@refill -@end deffn +@defun last lst n +@code{last} returns the last @var{n} elements of @var{lst}. @var{n} +must be a non-negative integer. +Example: +@lisp +(last '(foo bar baz bang) 2) + @result{} (baz bang) +(last '(1 2 3) 0) + @result{} 0 +@end lisp +@end defun -@node String Search, Tektronix Graphics Support, String Ports, Procedures -@section String Search +@defun butlast lst n +@code{butlast} returns all but the last @var{n} elements of +@var{lst}.@refill -@code{(require 'string-search)} +Example: +@lisp +(butlast '(a b c d) 3) + @result{} (a) +(butlast '(a b c d) 4) + @result{} () +@end lisp +@end defun -@deffn Procedure string-index string char -Returns the index of the first occurence of @var{char} within -@var{string}, or @code{#f} if the @var{string} does not contain a -character @var{char}. -@end deffn +@noindent +@code{last} and @code{butlast} split a list into two parts when given +identical arugments. +@example +(last '(a b c d e) 2) + @result{} (d e) +(butlast '(a b c d e) 2) + @result{} (a b c) +@end example -@deffn procedure substring? pattern string -Searches @var{string} to see if some substring of @var{string} is equal -to @var{pattern}. @code{substring?} returns the index of the first -character of the first substring of @var{string} that is equal to -@var{pattern}; or @code{#f} if @var{string} does not contain -@var{pattern}. +@defun nthcdr n lst +@code{nthcdr} takes @var{n} @code{cdr}s of @var{lst} and returns the +result. Thus @code{(nthcdr 3 @var{lst})} @equiv{} @code{(cdddr +@var{lst})} + +Example: +@lisp +(nthcdr 2 '(a b c d)) + @result{} (c d) +(nthcdr 0 '(a b c d)) + @result{} (a b c d) +@end lisp +@end defun + +@defun butnthcdr n lst +@code{butnthcdr} returns all but the nthcdr @var{n} elements of +@var{lst}.@refill + +Example: +@lisp +(butnthcdr 3 '(a b c d)) + @result{} (a b c) +(butnthcdr 4 '(a b c d)) + @result{} () +@end lisp +@end defun +@noindent +@code{nthcdr} and @code{butnthcdr} split a list into two parts when +given identical arugments. @example -(substring? "rat" "pirate") @result{} 2 -(substring? "rat" "outrage") @result{} #f -(substring? "" any-string) @result{} 0 +(nthcdr 2 '(a b c d e)) + @result{} (c d e) +(butnthcdr 2 '(a b c d e)) + @result{} (a b) @end example -@end deffn -@deffn Procedure find-string-from-port? str in-port max-no-chars -@deffnx Procedure find-string-from-port? str in-port -Looks for a string @var{str} within the first @var{max-no-chars} chars -of the input port @var{in-port}. @var{max-no-chars} may be omitted: in -that case, the search span is limited by the end of the input stream. -When the @var{str} is found, the function returns the number of -characters it has read from the port, and the port is set to read the -first char after that (that is, after the @var{str}) The function -returns @code{#f} when the @var{str} isn't found. -@code{find-string-from-port?} reads the port @emph{strictly} -sequentially, and does not perform any buffering. So -@code{find-string-from-port?} can be used even if the @var{in-port} is -open to a pipe or other communication channel. -@end deffn +@node Destructive list operations, Non-List functions, Lists as sequences, Common List Functions +@subsubsection Destructive list operations -@node Tektronix Graphics Support, Tree Operations, String Search, Procedures -@section Tektronix Graphics Support +These procedures may mutate the list they operate on, but any such +mutation is undefined. -@emph{Note:} The Tektronix graphics support files need more work, and -are not complete. +@deffn Procedure nconc args +@code{nconc} destructively concatenates its arguments. (Compare this +with @code{append}, which copies arguments rather than destroying them.) +Sometimes called @code{append!} (@xref{Rev2 Procedures}).@refill -@subsection Tektronix 4000 Series Graphics +Example: You want to find the subsets of a set. Here's the obvious way: -The Tektronix 4000 series graphics protocol gives the user a 1024 by -1024 square drawing area. The origin is in the lower left corner of the -screen. Increasing y is up and increasing x is to the right. +@lisp +(define (subsets set) + (if (null? set) + '(()) + (append (mapcar (lambda (sub) (cons (car set) sub)) + (subsets (cdr set))) + (subsets (cdr set))))) +@end lisp +But that does way more consing than you need. Instead, you could +replace the @code{append} with @code{nconc}, since you don't have any +need for all the intermediate results.@refill -The graphics control codes are sent over the current-output-port and can -be mixed with regular text and ANSI or other terminal control sequences. +Example: +@lisp +(define x '(a b c)) +(define y '(d e f)) +(nconc x y) + @result{} (a b c d e f) +x + @result{} (a b c d e f) +@end lisp -@deffn Procedure tek40:init +@code{nconc} is the same as @code{append!} in @file{sc2.scm}. @end deffn -@deffn Procedure tek40:graphics -@end deffn +@deffn Procedure nreverse lst +@code{nreverse} reverses the order of elements in @var{lst} by mutating +@code{cdr}s of the list. Sometimes called @code{reverse!}.@refill -@deffn Procedure tek40:text -@end deffn +Example: +@lisp +(define foo '(a b c)) +(nreverse foo) + @result{} (c b a) +foo + @result{} (a) +@end lisp -@deffn Procedure tek40:linetype linetype +Some people have been confused about how to use @code{nreverse}, +thinking that it doesn't return a value. It needs to be pointed out +that@refill +@lisp +(set! lst (nreverse lst)) +@end lisp +@noindent +is the proper usage, not +@lisp +(nreverse lst) +@end lisp +The example should suffice to show why this is the case. @end deffn -@deffn Procedure tek40:move x y -@end deffn +@deffn Procedure delete elt lst +@deffnx Procedure delete-if pred lst +@deffnx Procedure delete-if-not pred lst +Destructive versions of @code{remove} @code{remove-if}, and +@code{remove-if-not}.@refill -@deffn Procedure tek40:draw x y -@end deffn +Example: +@lisp +(define lst '(foo bar baz bang)) +(delete 'foo lst) + @result{} (bar baz bang) +lst + @result{} (foo bar baz bang) -@deffn Procedure tek40:put-text x y str -@end deffn +(define lst '(1 2 3 4 5 6 7 8 9)) +(delete-if odd? lst) + @result{} (2 4 6 8) +lst + @result{} (1 2 4 6 8) +@end lisp -@deffn Procedure tek40:reset +Some people have been confused about how to use @code{delete}, +@code{delete-if}, and @code{delete-if}, thinking that they dont' return +a value. It needs to be pointed out that@refill +@lisp +(set! lst (delete el lst)) +@end lisp +@noindent +is the proper usage, not +@lisp +(delete el lst) +@end lisp +The examples should suffice to show why this is the case. @end deffn -@subsection Tektronix 4100 Series Graphics -The graphics control codes are sent over the current-output-port and can -be mixed with regular text and ANSI or other terminal control sequences. - -@deffn Procedure tek41:init -@end deffn - -@deffn Procedure tek41:reset -@end deffn +@node Non-List functions, , Destructive list operations, Common List Functions +@subsubsection Non-List functions -@deffn Procedure tek41:graphics -@end deffn +@defun and? . args +@code{and?} checks to see if all its arguments are true. If they are, +@code{and?} returns @code{#t}, otherwise, @code{#f}. (In contrast to +@code{and}, this is a function, so all arguments are always evaluated +and in an unspecified order.)@refill -@deffn Procedure tek41:move x y -@end deffn +Example: +@lisp +(and? 1 2 3) + @result{} #t +(and #f 1 2) + @result{} #f +@end lisp +@end defun -@deffn Procedure tek41:draw x y -@end deffn +@defun or? . args +@code{or?} checks to see if any of its arguments are true. If any is +true, @code{or?} returns @code{#t}, and @code{#f} otherwise. (To +@code{or} as @code{and?} is to @code{and}.)@refill -@deffn Procedure tek41:point x y number -@end deffn +Example: +@lisp +(or? 1 2 #f) + @result{} #t +(or? #f #f #f) + @result{} #f +@end lisp +@end defun -@deffn Procedure tek41:encode-x-y x y -@end deffn +@defun atom? object +Returns @code{#t} if @var{object} is not a pair and @code{#f} if it is +pair. (Called @code{atom} in Common LISP.) +@lisp +(atom? 1) + @result{} #t +(atom? '(1 2)) + @result{} #f +(atom? #(1 2)) ; dubious! + @result{} #t +@end lisp +@end defun -@deffn Procedure tek41:encode-int number -@end deffn +@defun type-of object +Returns a symbol name for the type of @var{object}. +@end defun +@defun coerce object result-type +Converts and returns @var{object} of type @code{char}, @code{number}, +@code{string}, @code{symbol}, @code{list}, or @code{vector} to +@var{result-type} (which must be one of these symbols). +@end defun -@node Tree Operations, , Tektronix Graphics Support, Procedures -@section Tree operations +@node Tree Operations, Chapter Ordering, Common List Functions, Procedures +@subsection Tree operations @code{(require 'tree)} +@ftindex tree These are operations that treat lists a representations of trees. @@ -7663,1330 +9201,1215 @@ Examples: (subst '(a . cons) '(old . pair) '((old . spice) ((old . shoes) old . pair) (old . pair))) @result{} ((old . spice) ((old . shoes) a . cons) (a . cons)) -@end lisp -@end defun - -@defun copy-tree tree -Makes a copy of the nested list structure @var{tree} using new pairs and -returns it. All levels are copied, so that none of the pairs in the -tree are @code{eq?} to the original ones -- only the leaves are.@refill - -Example: -@lisp -(define bar '(bar)) -(copy-tree (list bar 'foo)) - @result{} ((bar) foo) -(eq? bar (car (copy-tree (list bar 'foo)))) - @result{} #f -@end lisp -@end defun - - - - - -@node Standards Support, Session Support, Procedures, Top -@chapter Standards Support - - - -@menu -* With-File:: 'with-file -* Transcripts:: 'transcript -* Rev2 Procedures:: 'rev2-procedures -* Rev4 Optional Procedures:: 'rev4-optional-procedures -* Multi-argument / and -:: 'multiarg/and- -* Multi-argument Apply:: 'multiarg-apply -* Rationalize:: 'rationalize -* Promises:: 'promise -* Dynamic-Wind:: 'dynamic-wind -* Values:: 'values -* Time:: 'time -* CLTime:: 'common-lisp-time -@end menu - -@node With-File, Transcripts, Standards Support, Standards Support -@section With-File - -@code{(require 'with-file)} - -@defun with-input-from-file file thunk -@defunx with-output-to-file file thunk -Description found in R4RS. -@end defun - -@node Transcripts, Rev2 Procedures, With-File, Standards Support -@section Transcripts - -@code{(require 'transcript)} - -@defun transcript-on filename -@defunx transcript-off filename -Redefines @code{read-char}, @code{read}, @code{write-char}, -@code{write}, @code{display}, and @code{newline}.@refill -@end defun - - - - - -@node Rev2 Procedures, Rev4 Optional Procedures, Transcripts, Standards Support -@section Rev2 Procedures - -@code{(require 'rev2-procedures)} - -The procedures below were specified in the @cite{Revised^2 Report on -Scheme}. @strong{N.B.}: The symbols @code{1+} and @code{-1+} are not -@cite{R4RS} syntax. Scheme->C, for instance, barfs on this -module.@refill - -@deffn Procedure substring-move-left! string1 start1 end1 string2 start2 -@deffnx Procedure substring-move-right! string1 start1 end1 string2 start2 -@var{string1} and @var{string2} must be a strings, and @var{start1}, -@var{start2} and @var{end1} must be exact integers satisfying@refill - -@display -0 <= @var{start1} <= @var{end1} <= (string-length @var{string1}) -0 <= @var{start2} <= @var{end1} - @var{start1} + @var{start2} <= (string-length @var{string2}) -@end display - -@code{substring-move-left!} and @code{substring-move-right!} store -characters of @var{string1} beginning with index @var{start1} -(inclusive) and ending with index @var{end1} (exclusive) into -@var{string2} beginning with index @var{start2} (inclusive).@refill - -@code{substring-move-left!} stores characters in time order of -increasing indices. @code{substring-move-right!} stores characters in -time order of increasing indeces.@refill -@end deffn - -@deffn Procedure substring-fill! string start end char -Fills the elements @var{start}--@var{end} of @var{string} with the -character @var{char}.@refill -@end deffn - -@defun string-null? str -@equiv{} @code{(= 0 (string-length @var{str}))} -@end defun - -@deffn Procedure append! . pairs -Destructively appends its arguments. Equivalent to @code{nconc}. -@end deffn - -@defun 1+ n -Adds 1 to @var{n}. -@end defun - -@defun -1+ n -Subtracts 1 from @var{n}. -@end defun - -@defun ? -@defunx >=? -These are equivalent to the procedures of the same name but without the -trailing @samp{?}. +@end lisp @end defun +@defun copy-tree tree +Makes a copy of the nested list structure @var{tree} using new pairs and +returns it. All levels are copied, so that none of the pairs in the +tree are @code{eq?} to the original ones -- only the leaves are.@refill +Example: +@lisp +(define bar '(bar)) +(copy-tree (list bar 'foo)) + @result{} ((bar) foo) +(eq? bar (car (copy-tree (list bar 'foo)))) + @result{} #f +@end lisp +@end defun -@node Rev4 Optional Procedures, Multi-argument / and -, Rev2 Procedures, Standards Support -@section Rev4 Optional Procedures -@code{(require 'rev4-optional-procedures)} +@node Chapter Ordering, Sorting, Tree Operations, Procedures +@subsection Chapter Ordering -For the specification of these optional procedures, -@xref{Standard procedures, , ,r4rs, Revised(4) Scheme}. +@code{(require 'chapter-order)} +@ftindex chapter-order -@defun list-tail l p -@end defun +The @samp{chap:} functions deal with strings which are ordered like +chapter numbers (or letters) in a book. Each section of the string +consists of consecutive numeric or consecutive aphabetic characters of +like case. -@defun string->list s -@end defun +@defun chap:stringstring l -@end defun +@example +(chap:string? string1 string2 +@defunx chap:string<=? string1 string2 +@defunx chap:string>=? string1 string2 +Implement the corresponding chapter-order predicates. @end defun -@deffn Procedure string-fill! s obj -@end deffn +@defun chap:next-string string +Returns the next string in the @emph{chapter order}. If @var{string} +has no alphabetic or numeric characters, +@code{(string-append @var{string} "0")} is returnd. The argument to +chap:next-string will always be @code{chap:stringvector l -@end defun +@example +(chap:next-string "a.9") @result{} "a.10" +(chap:next-string "4c") @result{} "4d" +(chap:next-string "4z") @result{} "4aa" +(chap:next-string "Revised^@{4@}") @result{} "Revised^@{5@}" -@defun vector->list s +@end example @end defun -@deffn Procedure vector-fill! s obj -@end deffn - +@node Sorting, Topological Sort, Chapter Ordering, Procedures +@subsection Sorting +@code{(require 'sort)} +@ftindex sort +Many Scheme systems provide some kind of sorting functions. They do +not, however, always provide the @emph{same} sorting functions, and +those that I have had the opportunity to test provided inefficient ones +(a common blunder is to use quicksort which does not perform well). -@node Multi-argument / and -, Multi-argument Apply, Rev4 Optional Procedures, Standards Support -@section Multi-argument / and - - -@code{(require 'mutliarg/and-)} - -For the specification of these optional forms, @xref{Numerical -operations, , ,r4rs, Revised(4) Scheme}. The @code{two-arg:}* forms are -only defined if the implementation does not support the many-argument -forms.@refill - -@defun two-arg:/ n1 n2 -The original two-argument version of @code{/}. -@end defun - -@defun / divident . divisors -@end defun +Because @code{sort} and @code{sort!} are not in the standard, there is +very little agreement about what these functions look like. For +example, Dybvig says that Chez Scheme provides +@lisp +(merge predicate list1 list2) +(merge! predicate list1 list2) +(sort predicate list) +(sort! predicate list) +@end lisp +@noindent +while MIT Scheme 7.1, following Common LISP, offers unstable +@lisp +(sort list predicate) +@end lisp +@noindent +TI PC Scheme offers +@lisp +(sort! list/vector predicate?) +@end lisp +@noindent +and Elk offers +@lisp +(sort list/vector predicate?) +(sort! list/vector predicate?) +@end lisp -@defun two-arg:- n1 n2 -The original two-argument version of @code{-}. -@end defun +Here is a comprehensive catalogue of the variations I have found. -@defun - minuend . subtrahends -@end defun +@enumerate +@item +Both @code{sort} and @code{sort!} may be provided. +@item +@code{sort} may be provided without @code{sort!}. +@item +@code{sort!} may be provided without @code{sort}. +@item +Neither may be provided. +@item +The sequence argument may be either a list or a vector. +@item +The sequence argument may only be a list. +@item +The sequence argument may only be a vector. +@item +The comparison function may be expected to behave like @code{<}. +@item +The comparison function may be expected to behave like @code{<=}. +@item +The interface may be @code{(sort predicate? sequence)}. +@item +The interface may be @code{(sort sequence predicate?)}. +@item +The interface may be @code{(sort sequence &optional (predicate? <))}. +@item +The sort may be stable. +@item +The sort may be unstable. +@end enumerate +All of this variation really does not help anybody. A nice simple merge +sort is both stable and fast (quite a lot faster than @emph{quick} sort). +I am providing this source code with no restrictions at all on its use +(but please retain D.H.D.Warren's credit for the original idea). You +may have to rename some of these functions in order to use them in a +system which already provides incompatible or inferior sorts. For each +of the functions, only the top-level define needs to be edited to do +that. +I could have given these functions names which would not clash with any +Scheme that I know of, but I would like to encourage implementors to +converge on a single interface, and this may serve as a hint. The +argument order for all functions has been chosen to be as close to +Common LISP as made sense, in order to avoid NIH-itis. +Each of the five functions has a required @emph{last} parameter which is +a comparison function. A comparison function @code{f} is a function of +2 arguments which acts like @code{<}. For example,@refill -@node Multi-argument Apply, Rationalize, Multi-argument / and -, Standards Support -@section Multi-argument Apply +@lisp +(not (f x x)) +(and (f x y) (f y z)) @equiv{} (f x z) +@end lisp -@code{(require 'multiarg-apply)} +The standard functions @code{<}, @code{>}, @code{char?}, +@code{char-ci?}, @code{string?}, +@code{string-ci?} are suitable for use as +comparison functions. Think of @code{(less? x y)} as saying when +@code{x} must @emph{not} precede @code{y}.@refill -@noindent -For the specification of this optional form, -@xref{Control features, , ,r4rs, Revised(4) Scheme}. +@defun sorted? sequence less? +Returns @code{#t} when the sequence argument is in non-decreasing order +according to @var{less?} (that is, there is no adjacent pair @code{@dots{} x +y @dots{}} for which @code{(less? y x)}).@refill -@defun two-arg:apply proc l -The implementation's native @code{apply}. Only defined for -implementations which don't support the many-argument version. +Returns @code{#f} when the sequence contains at least one out-of-order +pair. It is an error if the sequence is neither a list nor a vector. @end defun -@defun apply proc . args +@defun merge list1 list2 less? +This merges two lists, producing a completely new list as result. I +gave serious consideration to producing a Common-LISP-compatible +version. However, Common LISP's @code{sort} is our @code{sort!} (well, +in fact Common LISP's @code{stable-sort} is our @code{sort!}, merge sort +is @emph{fast} as well as stable!) so adapting CL code to Scheme takes a +bit of work anyway. I did, however, appeal to CL to determine the +@emph{order} of the arguments. @end defun +@deffn Procedure merge! list1 list2 less? +Merges two lists, re-using the pairs of @var{list1} and @var{list2} to +build the result. If the code is compiled, and @var{less?} constructs +no new pairs, no pairs at all will be allocated. The first pair of the +result will be either the first pair of @var{list1} or the first pair of +@var{list2}, but you can't predict which. +The code of @code{merge} and @code{merge!} could have been quite a bit +simpler, but they have been coded to reduce the amount of work done per +iteration. (For example, we only have one @code{null?} test per +iteration.)@refill +@end deffn +@defun sort sequence less? +Accepts either a list or a vector, and returns a new sequence which is +sorted. The new sequence is the same type as the input. Always +@code{(sorted? (sort sequence less?) less?)}. The original sequence is +not altered in any way. The new sequence shares its @emph{elements} +with the old one; no elements are copied.@refill +@end defun +@deffn Procedure sort! sequence less? +Returns its sorted result in the original boxes. If the original +sequence is a list, no new storage is allocated at all. If the original +sequence is a vector, the sorted elements are put back in the same +vector. -@node Rationalize, Promises, Multi-argument Apply, Standards Support -@section Rationalize - -@code{(require 'rationalize)} +Some people have been confused about how to use @code{sort!}, thinking +that it doesn't return a value. It needs to be pointed out that +@lisp +(set! slist (sort! slist <)) +@end lisp +@noindent +is the proper usage, not +@lisp +(sort! slist <) +@end lisp +@end deffn -The procedure rationalize is interesting because most programming -languages do not provide anything analogous to it. For simplicity, we -present an algorithm which computes the correct result for exact -arguments (provided the implementation supports exact rational numbers -of unlimited precision), and produces a reasonable answer for inexact -arguments when inexact arithmetic is implemented using floating-point. -We thank Alan Bawden for contributing this algorithm. +Note that these functions do @emph{not} accept a CL-style @samp{:key} +argument. A simple device for obtaining the same expressiveness is to +define@refill +@lisp +(define (keyed less? key) + (lambda (x y) (less? (key x) (key y)))) +@end lisp +@noindent +and then, when you would have written +@lisp +(sort a-sequence #'my-less :key #'my-key) +@end lisp +@noindent +in Common LISP, just write +@lisp +(sort! a-sequence (keyed my-less? my-key)) +@end lisp +@noindent +in Scheme. -@defun rationalize x e -@end defun +@node Topological Sort, String-Case, Sorting, Procedures +@subsection Topological Sort +@code{(require 'topological-sort)} or @code{(require 'tsort)} +@ftindex topological-sort +@ftindex tsort +@noindent +The algorithm is inspired by Cormen, Leiserson and Rivest (1990) +@cite{Introduction to Algorithms}, chapter 23. +@defun tsort dag pred +@defunx topological-sort dag pred +where +@table @var +@item dag +is a list of sublists. The car of each sublist is a vertex. The cdr is +the adjacency list of that vertex, i.e. a list of all vertices to which +there exists an edge from the car vertex. +@item pred +is one of @code{eq?}, @code{eqv?}, @code{equal?}, @code{=}, +@code{char=?}, @code{char-ci=?}, @code{string=?}, or @code{string-ci=?}. +@end table +Sort the directed acyclic graph @var{dag} so that for every edge from +vertex @var{u} to @var{v}, @var{u} will come before @var{v} in the +resulting list of vertices. -@node Promises, Dynamic-Wind, Rationalize, Standards Support -@section Promises +Time complexity: O (|V| + |E|) -@code{(require 'promise)} +Example (from Cormen): +@quotation +Prof. Bumstead topologically sorts his clothing when getting +dressed. The first argument to `tsort' describes which +garments he needs to put on before others. (For example, +Prof Bumstead needs to put on his shirt before he puts on his +tie or his belt.) `tsort' gives the correct order of dressing: +@end quotation -@defun make-promise proc +@example +(require 'tsort) +@ftindex tsort +(tsort '((shirt tie belt) + (tie jacket) + (belt jacket) + (watch) + (pants shoes belt) + (undershorts pants shoes) + (socks shoes)) + eq?) +@result{} +(socks undershorts pants shoes watch shirt belt tie jacket) +@end example @end defun -Change occurrences of @code{(delay @var{expression})} to -@code{(make-promise (lambda () @var{expression}))} and @code{(define -force promise:force)} to implement promises if your implementation -doesn't support them -(@pxref{Control features, , ,r4rs, Revised(4) Scheme}). - - - - -@node Dynamic-Wind, Values, Promises, Standards Support -@section Dynamic-Wind - -@code{(require 'dynamic-wind)} -This facility is a generalization of Common LISP @code{unwind-protect}, -designed to take into account the fact that continuations produced by -@code{call-with-current-continuation} may be reentered.@refill -@deffn Procedure dynamic-wind thunk1 thunk2 thunk3 -The arguments @var{thunk1}, @var{thunk2}, and @var{thunk3} must all be -procedures of no arguments (thunks).@refill +@node String-Case, String Ports, Topological Sort, Procedures +@subsection String-Case -@code{dynamic-wind} calls @var{thunk1}, @var{thunk2}, and then -@var{thunk3}. The value returned by @var{thunk2} is returned as the -result of @code{dynamic-wind}. @var{thunk3} is also called just before -control leaves the dynamic context of @var{thunk2} by calling a -continuation created outside that context. Furthermore, @var{thunk1} is -called before reentering the dynamic context of @var{thunk2} by calling -a continuation created inside that context. (Control is inside the -context of @var{thunk2} if @var{thunk2} is on the current return stack). +@code{(require 'string-case)} +@ftindex string-case -@strong{Warning:} There is no provision for dealing with errors or -interrupts. If an error or interrupt occurs while using -@code{dynamic-wind}, the dynamic environment will be that in effect at -the time of the error or interrupt.@refill +@deffn Procedure string-upcase str +@deffnx Procedure string-downcase str +@deffnx Procedure string-capitalize str +The obvious string conversion routines. These are non-destructive. @end deffn +@defun string-upcase! str +@defunx string-downcase! str +@defunx string-captialize! str +The destructive versions of the functions above. +@end defun -@node Values, Time, Dynamic-Wind, Standards Support -@section Values -@code{(require 'values)} -@defun values obj @dots{} -@code{values} takes any number of arguments, and passes (returns) them -to its continuation.@refill -@end defun +@node String Ports, String Search, String-Case, Procedures +@subsection String Ports +@code{(require 'string-port)} +@ftindex string-port -@defun call-with-values thunk proc -@var{thunk} must be a procedure of no arguments, and @var{proc} must be -a procedure. @code{call-with-values} calls @var{thunk} with a -continuation that, when passed some values, calls @var{proc} with those -values as arguments.@refill +@deffn Procedure call-with-output-string proc +@var{proc} must be a procedure of one argument. This procedure calls +@var{proc} with one argument: a (newly created) output port. When the +function returns, the string composed of the characters written into the +port is returned.@refill +@end deffn -Except for continuations created by the @code{call-with-values} -procedure, all continuations take exactly one value, as now; the effect -of passing no value or more than one value to continuations that were -not created by the @code{call-with-values} procedure is -unspecified.@refill -@end defun +@deffn Procedure call-with-input-string string proc +@var{proc} must be a procedure of one argument. This procedure calls +@var{proc} with one argument: an (newly created) input port from which +@var{string}'s contents may be read. When @var{proc} returns, the port +is closed and the value yielded by the procedure @var{proc} is +returned.@refill +@end deffn -@node Time, CLTime, Values, Standards Support -@section Time -The procedures @code{current-time}, @code{difftime}, and -@code{offset-time} are supported by all implementations (SLIB provides -them if feature @code{('current-time)} is missing. @code{current-time} -returns a @dfn{calendar time} (caltime) which can be a number or other -type. +@node String Search, Line I/O, String Ports, Procedures +@subsection String Search -@defun current-time -Returns the time since 00:00:00 GMT, January 1, 1970, measured in -seconds. Note that the reference time is different from the reference -time for @code{get-universal-time} in @ref{CLTime}. On implementations -which cannot support actual times, @code{current-time} will increment a -counter and return its value when called. -@end defun +@code{(require 'string-search)} +@ftindex string-search -@defun difftime caltime1 caltime0 -Returns the difference (number of seconds) between twe calendar times: -@var{caltime1} - @var{caltime0}. @var{caltime0} can also be a number. -@end defun +@deffn Procedure string-index string char +@deffnx Procedure string-index-ci string char +Returns the index of the first occurence of @var{char} within +@var{string}, or @code{#f} if the @var{string} does not contain a +character @var{char}. +@end deffn -@defun offset-time caltime offset -Returns the calendar time of @var{caltime} offset by @var{offset} number -of seconds @code{(+ caltime offset)}. -@end defun +@deffn Procedure string-reverse-index string char +@deffnx Procedure string-reverse-index-ci string char +Returns the index of the last occurence of @var{char} within +@var{string}, or @code{#f} if the @var{string} does not contain a +character @var{char}. +@end deffn + +@deffn procedure substring? pattern string +@deffnx procedure substring-ci? pattern string +Searches @var{string} to see if some substring of @var{string} is equal +to @var{pattern}. @code{substring?} returns the index of the first +character of the first substring of @var{string} that is equal to +@var{pattern}; or @code{#f} if @var{string} does not contain +@var{pattern}. @example -(require 'posix-time) +(substring? "rat" "pirate") @result{} 2 +(substring? "rat" "outrage") @result{} #f +(substring? "" any-string) @result{} 0 @end example +@end deffn -These procedures are intended to be compatible with Posix time -conversion functions. +@deffn Procedure find-string-from-port? str in-port max-no-chars +Looks for a string @var{str} within the first @var{max-no-chars} chars +of the input port @var{in-port}. +@deffnx Procedure find-string-from-port? str in-port +When called with two arguments, the search span is limited by the end of +the input stream. +@deffnx Procedure find-string-from-port? str in-port char +Searches up to the first occurrence of character @var{char} in +@var{str}. +@deffnx Procedure find-string-from-port? str in-port proc +Searches up to the first occurrence of the procedure @var{proc} +returning non-false when called with a character (from @var{in-port}) +argument. + +When the @var{str} is found, @code{find-string-from-port?} returns the +number of characters it has read from the port, and the port is set to +read the first char after that (that is, after the @var{str}) The +function returns @code{#f} when the @var{str} isn't found. -@defvar *timezone* -contains the difference, in seconds, between UTC and local standard time -(for example, in the U.S. Eastern time zone (EST), timezone is -5*60*60). @code{*timezone*} is initialized by @code{tzset}. -@end defvar +@code{find-string-from-port?} reads the port @emph{strictly} +sequentially, and does not perform any buffering. So +@code{find-string-from-port?} can be used even if the @var{in-port} is +open to a pipe or other communication channel. +@end deffn -@defun tzset -initializes the @var{*timezone*} variable from the TZ environment -variable. This function is automatically called by the other time -conversion functions that depend on the time zone. -@end defun -@defun gmtime caltime -converts the calendar time @var{caltime} to a vector of integers -representing the time expressed as Coordinated Universal Time (UTC). +@node Line I/O, Multi-Processing, String Search, Procedures +@subsection Line I/O -@defunx localtime caltime -converts the calendar time @var{caltime} to a vector of integers expressed -relative to the user's time zone. @code{localtime} sets the variable -@var{*timezone*} with the difference between Coordinated Universal Time -(UTC) and local standard time in seconds by calling @code{tzset}. -The elements of the returned vector are as follows: +@code{(require 'line-i/o)} +@ftindex line-i -@enumerate 0 -@item - seconds (0 - 61) -@item - minutes (0 - 59) -@item - hours since midnight -@item - day of month -@item - month (0 - 11). Note difference from @code{decode-universal-time}. -@item - year (A.D.) -@item - day of week (0 - 6) -@item - day of year (0 - 365) -@item - 1 for daylight savings, 0 for regular time -@end enumerate +@defun read-line +@defunx read-line port +Returns a string of the characters up to, but not including a newline or +end of file, updating @var{port} to point to the character following the +newline. If no characters are available, an end of file object is +returned. @var{port} may be omitted, in which case it defaults to the +value returned by @code{current-input-port}.@refill @end defun -@defun mktime univtime -Converts a vector of integers in Coordinated Universal Time (UTC) format -to calendar time (caltime) format. +@defun read-line! string +@defunx read-line! string port +Fills @var{string} with characters up to, but not including a newline or +end of file, updating the port to point to the last character read or +following the newline if it was read. If no characters are available, +an end of file object is returned. If a newline or end of file was +found, the number of characters read is returned. Otherwise, @code{#f} +is returned. @var{port} may be omitted, in which case it defaults to +the value returned by @code{current-input-port}.@refill @end defun -@defun asctime univtime -Converts the vector of integers @var{caltime} in Coordinated -Universal Time (UTC) format into a string of the form -@code{"Wed Jun 30 21:49:08 1993"}. +@defun write-line string +@defunx write-line string port +Writes @var{string} followed by a newline to the given port and returns +an unspecified value. Port may be omited, in which case it defaults to +the value returned by @code{current-input-port}.@refill @end defun -@defun ctime caltime -Equivalent to @code{(time:asctime (time:localtime @var{caltime}))}. -@end defun -@node CLTime, , Time, Standards Support -@section CLTime -@defun get-decoded-time -Equivalent to @code{(decode-universal-time (get-universal-time))}. -@end defun -@defun get-universal-time -Returns the current time as @dfn{Universal Time}, number of seconds -since 00:00:00 Jan 1, 1900 GMT. Note that the reference time is -different from @code{current-time}. -@end defun +@node Multi-Processing, , Line I/O, Procedures +@subsection Multi-Processing -@defun decode-universal-time univtime -Converts @var{univtime} to @dfn{Decoded Time} format. -Nine values are returned: -@enumerate 0 -@item - seconds (0 - 61) -@item - minutes (0 - 59) -@item - hours since midnight -@item - day of month -@item - month (1 - 12). Note difference from @code{gmtime} and @code{localtime}. -@item - year (A.D.) -@item - day of week (0 - 6) -@item - #t for daylight savings, #f otherwise -@item - hours west of GMT (-24 - +24) -@end enumerate +@code{(require 'process)} +@ftindex process + +This module implements asynchronous (non-polled) time-sliced +multi-processing in the SCM Scheme implementation using procedures +@code{alarm} and @code{alarm-interrupt}. +@findex alarm +@findex alarm-interrupt +Until this is ported to another implementation, consider it an example +of writing schedulers in Scheme. + +@deffn Procedure add-process! proc +Adds proc, which must be a procedure (or continuation) capable of +accepting accepting one argument, to the @code{process:queue}. The +value returned is unspecified. The argument to @var{proc} should be +ignored. If @var{proc} returns, the process is killed.@refill +@end deffn + +@deffn Procedure process:schedule! +Saves the current process on @code{process:queue} and runs the next +process from @code{process:queue}. The value returned is +unspecified.@refill +@end deffn -Notice that the values returned by @code{decode-universal-time} do not -match the arguments to @code{encode-universal-time}. -@end defun +@deffn Procedure kill-process! +Kills the current process and runs the next process from +@code{process:queue}. If there are no more processes on +@code{process:queue}, @code{(slib:exit)} is called (@xref{System}). +@end deffn -@defun encode-universal-time second minute hour date month year -@defunx encode-universal-time second minute hour date month year time-zone -Converts the arguments in Decoded Time format to Universal Time format. -If @var{time-zone} is not specified, the returned time is adjusted for -daylight saving time. Otherwise, no adjustment is performed. -Notice that the values returned by @code{decode-universal-time} do not -match the arguments to @code{encode-universal-time}. -@end defun + +@node Standards Support, Session Support, Procedures, Other Packages +@section Standards Support -@node Session Support, Optional SLIB Packages, Standards Support, Top -@chapter Session Support @menu -* Repl:: Macros at top-level -* Quick Print:: Loop-safe Output -* Debug:: To err is human ... -* Breakpoints:: Pause execution -* Trace:: 'trace -* Getopt:: Command Line option parsing -* Command Line:: A command line reader for Scheme shells -* System Interface:: 'system and 'getenv +* With-File:: 'with-file +* Transcripts:: 'transcript +* Rev2 Procedures:: 'rev2-procedures +* Rev4 Optional Procedures:: 'rev4-optional-procedures +* Multi-argument / and -:: 'multiarg/and- +* Multi-argument Apply:: 'multiarg-apply +* Rationalize:: 'rationalize +* Promises:: 'promise +* Dynamic-Wind:: 'dynamic-wind +* Values:: 'values +@end menu -Certain features are so simple, system-dependent, or widely subcribed -that they are supported by all implementations as part of the -@samp{*.init} files. +@node With-File, Transcripts, Standards Support, Standards Support +@subsection With-File -The features described in the following sections are provided by all -implementations. +@code{(require 'with-file)} +@ftindex with-file -* Require:: Module Management -* Vicinity:: Pathname Management -* Configuration:: Characteristics of Scheme Implementation -* Input/Output:: Things not provided by the Scheme specs. -* Legacy:: -* System:: LOADing, EVALing, ERRORing, and EXITing -@end menu +@defun with-input-from-file file thunk +@defunx with-output-to-file file thunk +Description found in R4RS. +@end defun +@node Transcripts, Rev2 Procedures, With-File, Standards Support +@subsection Transcripts +@code{(require 'transcript)} +@ftindex transcript -@node Repl, Quick Print, Session Support, Session Support -@section Repl +@defun transcript-on filename +@defunx transcript-off filename +Redefines @code{read-char}, @code{read}, @code{write-char}, +@code{write}, @code{display}, and @code{newline}.@refill +@end defun -@code{(require 'repl)} -Here is a read-eval-print-loop which, given an eval, evaluates forms. -@deffn Procedure repl:top-level repl:eval -@code{read}s, @code{repl:eval}s and @code{write}s expressions from -@code{(current-input-port)} to @code{(current-output-port)} until an -end-of-file is encountered. @code{load}, @code{slib:eval}, -@code{slib:error}, and @code{repl:quit} dynamically bound during -@code{repl:top-level}.@refill -@end deffn -@deffn Procedure repl:quit -Exits from the invocation of @code{repl:top-level}. -@end deffn -The @code{repl:} procedures establish, as much as is possible to do -portably, a top level environment supporting macros. -@code{repl:top-level} uses @code{dynamic-wind} to catch error conditions -and interrupts. If your implementation supports this you are all set. +@node Rev2 Procedures, Rev4 Optional Procedures, Transcripts, Standards Support +@subsection Rev2 Procedures -Otherwise, if there is some way your implementation can catch error -conditions and interrupts, then have them call @code{slib:error}. It -will display its arguments and reenter @code{repl:top-level}. -@code{slib:error} dynamically bound by @code{repl:top-level}.@refill +@code{(require 'rev2-procedures)} +@ftindex rev2-procedures -To have your top level loop always use macros, add any interrupt -catching lines and the following lines to your Scheme init file: -@lisp -(require 'macro) -(require 'repl) -(repl:top-level macro:eval) -@end lisp +The procedures below were specified in the @cite{Revised^2 Report on +Scheme}. @strong{N.B.}: The symbols @code{1+} and @code{-1+} are not +@cite{R4RS} syntax. Scheme->C, for instance, barfs on this +module.@refill -@node Quick Print, Debug, Repl, Session Support -@section Quick Print +@deffn Procedure substring-move-left! string1 start1 end1 string2 start2 +@deffnx Procedure substring-move-right! string1 start1 end1 string2 start2 +@var{string1} and @var{string2} must be a strings, and @var{start1}, +@var{start2} and @var{end1} must be exact integers satisfying@refill -@code{(require 'qp)} +@display +0 <= @var{start1} <= @var{end1} <= (string-length @var{string1}) +0 <= @var{start2} <= @var{end1} - @var{start1} + @var{start2} <= (string-length @var{string2}) +@end display -@noindent -When displaying error messages and warnings, it is paramount that the -output generated for circular lists and large data structures be -limited. This section supplies a procedure to do this. It could be -much improved. +@code{substring-move-left!} and @code{substring-move-right!} store +characters of @var{string1} beginning with index @var{start1} +(inclusive) and ending with index @var{end1} (exclusive) into +@var{string2} beginning with index @var{start2} (inclusive).@refill -@quotation -Notice that the neccessity for truncating output eliminates -Common-Lisp's @xref{Format} from consideration; even when variables -@code{*print-level*} and @code{*print-level*} are set, huge strings and -bit-vectors are @emph{not} limited. -@end quotation +@code{substring-move-left!} stores characters in time order of +increasing indices. @code{substring-move-right!} stores characters in +time order of increasing indeces.@refill +@end deffn -@deffn Procedure qp arg1 @dots{} -@deffnx Procedure qpn arg1 @dots{} -@deffnx Procedure qpr arg1 @dots{} -@code{qp} writes its arguments, separated by spaces, to -@code{(current-output-port)}. @code{qp} compresses printing by -substituting @samp{...} for substructure it does not have sufficient -room to print. @code{qpn} is like @code{qp} but outputs a newline -before returning. @code{qpr} is like @code{qpn} except that it returns -its last argument.@refill +@deffn Procedure substring-fill! string start end char +Fills the elements @var{start}--@var{end} of @var{string} with the +character @var{char}.@refill @end deffn -@defvar *qp-width* -@code{*qp-width*} is the largest number of characters that @code{qp} -should use.@refill -@end defvar +@defun string-null? str +@equiv{} @code{(= 0 (string-length @var{str}))} +@end defun -@node Debug, Breakpoints, Quick Print, Session Support -@section Debug +@deffn Procedure append! . pairs +Destructively appends its arguments. Equivalent to @code{nconc}. +@end deffn -@code{(require 'debug)} +@defun 1+ n +Adds 1 to @var{n}. +@end defun -@noindent -Requiring @code{debug} automatically requires @code{trace} and -@code{break}. +@defun -1+ n +Subtracts 1 from @var{n}. +@end defun -@noindent -An application with its own datatypes may want to substitute its own -printer for @code{qp}. This example shows how to do this: +@defun ? +@defunx >=? +These are equivalent to the procedures of the same name but without the +trailing @samp{?}. +@end defun -@example -(define qpn (lambda args) @dots{}) -(provide 'qp) -(require 'debug) -@end example -@deffn Procedure trace-all file -Traces (@pxref{Trace}) all procedures @code{define}d at top-level in -file @file{file}. -@end deffn -@deffn Procedure break-all file -Breakpoints (@pxref{Breakpoints}) all procedures @code{define}d at -top-level in file @file{file}. -@end deffn +@node Rev4 Optional Procedures, Multi-argument / and -, Rev2 Procedures, Standards Support +@subsection Rev4 Optional Procedures -@node Breakpoints, Trace, Debug, Session Support -@section Breakpoints +@code{(require 'rev4-optional-procedures)} +@ftindex rev4-optional-procedures -@code{(require 'break)} +For the specification of these optional procedures, +@xref{Standard procedures, , ,r4rs, Revised(4) Scheme}. -@defun init-debug -If your Scheme implementation does not support @code{break} or -@code{abort}, a message will appear when you @code{(require 'break)} or -@code{(require 'debug)} telling you to type @code{(init-debug)}. This -is in order to establish a top-level continuation. Typing -@code{(init-debug)} at top level sets up a continuation for -@code{break}. +@defun list-tail l p @end defun -@defun breakpoint arg1 @dots{} -Returns from the top level continuation and pushes the continuation from -which it was called on a continuation stack. +@defun string->list s @end defun -@defun continue -Pops the topmost continuation off of the continuation stack and returns -an unspecified value to it. -@defunx continue arg1 @dots{} -Pops the topmost continuation off of the continuation stack and returns -@var{arg1} @dots{} to it. +@defun list->string l @end defun -@defmac break proc1 @dots{} -Redefines the top-level named procedures given as arguments so that -@code{breakpoint} is called before calling @var{proc1} @dots{}. -@defmacx break -With no arguments, makes sure that all the currently broken identifiers -are broken (even if those identifiers have been redefined) and returns a -list of the broken identifiers. -@end defmac - -@defmac unbreak proc1 @dots{} -Turns breakpoints off for its arguments. -@defmacx unbreak -With no arguments, unbreaks all currently broken identifiers and returns -a list of these formerly broken identifiers. -@end defmac - -The following routines are the procedures which actually do the tracing -when this module is supplied by SLIB, rather than natively. If -defmacros are not natively supported by your implementation, these might -be more convenient to use. - -@defun breakf proc -@defunx breakf proc name -@defunx debug:breakf proc -@defunx debug:breakf proc name -To break, type -@lisp -(set! @var{symbol} (breakf @var{symbol})) -@end lisp -@noindent -or -@lisp -(set! @var{symbol} (breakf @var{symbol} '@var{symbol})) -@end lisp -@noindent -or -@lisp -(define @var{symbol} (breakf @var{function})) -@end lisp -@noindent -or -@lisp -(define @var{symbol} (breakf @var{function} '@var{symbol})) -@end lisp +@defun string-copy @end defun -@defun unbreakf proc -@defunx debug:unbreakf proc -To unbreak, type -@lisp -(set! @var{symbol} (unbreakf @var{symbol})) -@end lisp +@deffn Procedure string-fill! s obj +@end deffn + +@defun list->vector l @end defun -@node Trace, Getopt, Breakpoints, Session Support -@section Tracing +@defun vector->list s +@end defun -@code{(require 'trace)} +@deffn Procedure vector-fill! s obj +@end deffn -@defmac trace proc1 @dots{} -Traces the top-level named procedures given as arguments. -@defmacx trace -With no arguments, makes sure that all the currently traced identifiers -are traced (even if those identifiers have been redefined) and returns a -list of the traced identifiers. -@end defmac -@defmac untrace proc1 @dots{} -Turns tracing off for its arguments. -@defmacx untrace -With no arguments, untraces all currently traced identifiers and returns -a list of these formerly traced identifiers. -@end defmac -The following routines are the procedures which actually do the tracing -when this module is supplied by SLIB, rather than natively. If -defmacros are not natively supported by your implementation, these might -be more convenient to use. -@defun tracef proc -@defunx tracef proc name -@defunx debug:tracef proc -@defunx debug:tracef proc name -To trace, type -@lisp -(set! @var{symbol} (tracef @var{symbol})) -@end lisp -@noindent -or -@lisp -(set! @var{symbol} (tracef @var{symbol} '@var{symbol})) -@end lisp -@noindent -or -@lisp -(define @var{symbol} (tracef @var{function})) -@end lisp -@noindent -or -@lisp -(define @var{symbol} (tracef @var{function} '@var{symbol})) -@end lisp + +@node Multi-argument / and -, Multi-argument Apply, Rev4 Optional Procedures, Standards Support +@subsection Multi-argument / and - + +@code{(require 'mutliarg/and-)} +@ftindex mutliarg + +For the specification of these optional forms, @xref{Numerical +operations, , ,r4rs, Revised(4) Scheme}. The @code{two-arg:}* forms are +only defined if the implementation does not support the many-argument +forms.@refill + +@defun two-arg:/ n1 n2 +The original two-argument version of @code{/}. @end defun -@defun untracef proc -@defunx debug:untracef proc -To untrace, type -@lisp -(set! @var{symbol} (untracef @var{symbol})) -@end lisp +@defun / divident . divisors @end defun +@defun two-arg:- n1 n2 +The original two-argument version of @code{-}. +@end defun -@node Getopt, Command Line, Trace, Session Support -@section Getopt +@defun - minuend . subtrahends +@end defun -@code{(require 'getopt)} -This routine implements Posix command line argument parsing. Notice -that returning values through global variables means that @code{getopt} -is @emph{not} reentrant. -@defvar *optind* -Is the index of the current element of the command line. It is -initially one. In order to parse a new command line or reparse an old -one, @var{*opting*} must be reset. -@end defvar -@defvar *optarg* -Is set by getopt to the (string) option-argument of the current option. -@end defvar -@deffn Procedure getopt argc argv optstring -Returns the next option letter in @var{argv} (starting from -@code{(vector-ref argv *optind*)}) that matches a letter in -@var{optstring}. @var{argv} is a vector or list of strings, the 0th of -which getopt usually ignores. @var{argc} is the argument count, usually -the length of @var{argv}. @var{optstring} is a string of recognized -option characters; if a character is followed by a colon, the option -takes an argument which may be immediately following it in the string or -in the next element of @var{argv}. +@node Multi-argument Apply, Rationalize, Multi-argument / and -, Standards Support +@subsection Multi-argument Apply -@var{*optind*} is the index of the next element of the @var{argv} vector -to be processed. It is initialized to 1 by @file{getopt.scm}, and -@code{getopt} updates it when it finishes with each element of -@var{argv}. +@code{(require 'multiarg-apply)} +@ftindex multiarg-apply -@code{getopt} returns the next option character from @var{argv} that -matches a character in @var{optstring}, if there is one that matches. -If the option takes an argument, @code{getopt} sets the variable -@var{*optarg*} to the option-argument as follows: +@noindent +For the specification of this optional form, +@xref{Control features, , ,r4rs, Revised(4) Scheme}. -@itemize @bullet -@item -If the option was the last character in the string pointed to by an -element of @var{argv}, then @var{*optarg*} contains the next element of -@var{argv}, and @var{*optind*} is incremented by 2. If the resulting -value of @var{*optind*} is greater than or equal to @var{argc}, this -indicates a missing option argument, and @code{getopt} returns an error -indication. +@defun two-arg:apply proc l +The implementation's native @code{apply}. Only defined for +implementations which don't support the many-argument version. +@end defun -@item -Otherwise, @var{*optarg*} is set to the string following the option -character in that element of @var{argv}, and @var{*optind*} is -incremented by 1. -@end itemize +@defun apply proc . args +@end defun -If, when @code{getopt} is called, the string @code{(vector-ref argv -*optind*)} either does not begin with the character @code{#\-} or is -just @code{"-"}, @code{getopt} returns @code{#f} without changing -@var{*optind*}. If @code{(vector-ref argv *optind*)} is the string -@code{"--"}, @code{getopt} returns @code{#f} after incrementing -@var{*optind*}. -If @code{getopt} encounters an option character that is not contained in -@var{optstring}, it returns the question-mark @code{#\?} character. If -it detects a missing option argument, it returns the colon character -@code{#\:} if the first character of @var{optstring} was a colon, or a -question-mark character otherwise. In either case, @code{getopt} sets -the variable @var{getopt:opt} to the option character that caused the -error. -The special option @code{"--"} can be used to delimit the end of the -options; @code{#f} is returned, and @code{"--"} is skipped. -RETURN VALUE -@code{getopt} returns the next option character specified on the command -line. A colon @code{#\:} is returned if @code{getopt} detects a missing argument -and the first character of @var{optstring} was a colon @code{#\:}. +@node Rationalize, Promises, Multi-argument Apply, Standards Support +@subsection Rationalize -A question-mark @code{#\?} is returned if @code{getopt} encounters an option -character not in @var{optstring} or detects a missing argument and the first -character of @var{optstring} was not a colon @code{#\:}. +@code{(require 'rationalize)} +@ftindex rationalize -Otherwise, @code{getopt} returns @code{#f} when all command line options have been -parsed. +The procedure rationalize is interesting because most programming +languages do not provide anything analogous to it. For simplicity, we +present an algorithm which computes the correct result for exact +arguments (provided the implementation supports exact rational numbers +of unlimited precision), and produces a reasonable answer for inexact +arguments when inexact arithmetic is implemented using floating-point. +We thank Alan Bawden for contributing this algorithm. -Example: -@lisp -#! /usr/local/bin/scm -;;;This code is SCM specific. -(define argv (program-arguments)) -(require 'getopt) +@defun rationalize x e +@end defun -(define opts ":a:b:cd") -(let loop ((opt (getopt (length argv) argv opts))) - (case opt - ((#\a) (print "option a: " *optarg*)) - ((#\b) (print "option b: " *optarg*)) - ((#\c) (print "option c")) - ((#\d) (print "option d")) - ((#\?) (print "error" getopt:opt)) - ((#\:) (print "missing arg" getopt:opt)) - ((#f) (if (< *optind* (length argv)) - (print "argv[" *optind* "]=" - (list-ref argv *optind*))) - (set! *optind* (+ *optind* 1)))) - (if (< *optind* (length argv)) - (loop (getopt (length argv) argv opts)))) -(slib:exit) -@end lisp -@end deffn -@section Getopt-- -@defun getopt-- argc argv optstring -The procedure @code{getopt--} is an extended version of @code{getopt} -which parses @dfn{long option names} of the form -@samp{--hold-the-onions} and @samp{--verbosity-level=extreme}. -@w{@code{Getopt--}} behaves as @code{getopt} except for non-empty -options beginning with @samp{--}. -Options beginning with @samp{--} are returned as strings rather than -characters. If a value is assigned (using @samp{=}) to a long option, -@code{*optarg*} is set to the value. The @samp{=} and value are -not returned as part of the option string. +@node Promises, Dynamic-Wind, Rationalize, Standards Support +@subsection Promises -No information is passed to @code{getopt--} concerning which long -options should be accepted or whether such options can take arguments. -If a long option did not have an argument, @code{*optarg} will be set to -@code{#f}. The caller is responsible for detecting and reporting -errors. +@code{(require 'promise)} +@ftindex promise -@example -(define opts ":-:b:") -(define argc 5) -(define argv '("foo" "-b9" "--f1" "--2=" "--g3=35234.342" "--")) -(define *optind* 1) -(define *optarg* #f) -(require 'qp) -(do ((i 5 (+ -1 i))) - ((zero? i)) - (define opt (getopt-- argc argv opts)) - (print *optind* opt *optarg*))) -@print{} -2 #\b "9" -3 "f1" #f -4 "2" "" -5 "g3" "35234.342" -5 #f "35234.342" -@end example +@defun make-promise proc @end defun -@node Command Line, System Interface, Getopt, Session Support -@section Command Line +Change occurrences of @code{(delay @var{expression})} to +@code{(make-promise (lambda () @var{expression}))} and @code{(define +force promise:force)} to implement promises if your implementation +doesn't support them +(@pxref{Control features, , ,r4rs, Revised(4) Scheme}). + -@code{(require 'read-command)} -@defun read-command port -@defunx read-command -@code{read-command} converts a @dfn{command line} into a list of strings -suitable for parsing by @code{getopt}. The syntax of command lines -supported resembles that of popular @dfn{shell}s. @code{read-command} -updates @var{port} to point to the first character past the command -delimiter. -If an end of file is encountered in the input before any characters are -found that can begin an object or comment, then an end of file object is -returned. +@node Dynamic-Wind, Values, Promises, Standards Support +@subsection Dynamic-Wind -The @var{port} argument may be omitted, in which case it defaults to the -value returned by @code{current-input-port}. +@code{(require 'dynamic-wind)} +@ftindex dynamic-wind + +This facility is a generalization of Common LISP @code{unwind-protect}, +designed to take into account the fact that continuations produced by +@code{call-with-current-continuation} may be reentered.@refill + +@deffn Procedure dynamic-wind thunk1 thunk2 thunk3 +The arguments @var{thunk1}, @var{thunk2}, and @var{thunk3} must all be +procedures of no arguments (thunks).@refill + +@code{dynamic-wind} calls @var{thunk1}, @var{thunk2}, and then +@var{thunk3}. The value returned by @var{thunk2} is returned as the +result of @code{dynamic-wind}. @var{thunk3} is also called just before +control leaves the dynamic context of @var{thunk2} by calling a +continuation created outside that context. Furthermore, @var{thunk1} is +called before reentering the dynamic context of @var{thunk2} by calling +a continuation created inside that context. (Control is inside the +context of @var{thunk2} if @var{thunk2} is on the current return stack). -The fields into which the command line is split are delimited by -whitespace as defined by @code{char-whitespace?}. The end of a command -is delimited by end-of-file or unescaped semicolon (@key{;}) or -@key{newline}. Any character can be literally included in a field by -escaping it with a backslach (@key{\}). +@strong{Warning:} There is no provision for dealing with errors or +interrupts. If an error or interrupt occurs while using +@code{dynamic-wind}, the dynamic environment will be that in effect at +the time of the error or interrupt.@refill +@end deffn -The initial character and types of fields recognized are: -@table @asis -@item @samp{\} -The next character has is taken literally and not interpreted as a field -delimiter. If @key{\} is the last character before a @key{newline}, -that @key{newline} is just ignored. Processing continues from the -characters after the @key{newline} as though the backslash and -@key{newline} were not there. -@item @samp{"} -The characters up to the next unescaped @key{"} are taken literally, -according to [R4RS] rules for literal strings (@pxref{Strings, , ,r4rs, -Revised(4) Scheme}). -@item @samp{(}, @samp{%'} -One scheme expression is @code{read} starting with this character. The -@code{read} expression is evaluated, converted to a string -(using @code{display}), and replaces the expression in the returned -field. -@item @samp{;} -Semicolon delimits a command. Using semicolons more than one command -can appear on a line. Escaped semicolons and semicolons inside strings -do not delimit commands. -@end table -@noindent -The comment field differs from the previous fields in that it must be -the first character of a command or appear after whitespace in order to -be recognized. @key{#} can be part of fields if these conditions are -not met. For instance, @code{ab#c} is just the field ab#c. -@table @samp -@item # -Introduces a comment. The comment continues to the end of the line on -which the semicolon appears. Comments are treated as whitespace by -@code{read-dommand-line} and backslashes before @key{newline}s in -comments are also ignored. -@end table -@end defun -@node System Interface, Require, Command Line, Session Support -@section System Interface +@node Values, , Dynamic-Wind, Standards Support +@subsection Values -If @code{(provided? 'getenv)}: +@code{(require 'values)} +@ftindex values -@defun getenv name -Looks up @var{name}, a string, in the program environment. If @var{name} is -found a string of its value is returned. Otherwise, @code{#f} is returned. +@defun values obj @dots{} +@code{values} takes any number of arguments, and passes (returns) them +to its continuation.@refill @end defun -If @code{(provided? 'system)}: -@defun system command-string -Executes the @var{command-string} on the computer and returns the -integer status code. -@end defun +@defun call-with-values thunk proc +@var{thunk} must be a procedure of no arguments, and @var{proc} must be +a procedure. @code{call-with-values} calls @var{thunk} with a +continuation that, when passed some values, calls @var{proc} with those +values as arguments.@refill +Except for continuations created by the @code{call-with-values} +procedure, all continuations take exactly one value, as now; the effect +of passing no value or more than one value to continuations that were +not created by the @code{call-with-values} procedure is +unspecified.@refill +@end defun -@node Require, Vicinity, System Interface, Session Support -@section Require -These variables and procedures are provided by all implementations. +@node Session Support, Extra-SLIB Packages, Standards Support, Other Packages +@section Session Support -@defvar *features* -Is a list of symbols denoting features supported in this implementation. -@end defvar +@menu +* Repl:: Macros at top-level +* Quick Print:: Loop-safe Output +* Debug:: To err is human ... +* Breakpoints:: Pause execution +* Trace:: 'trace +* System Interface:: 'system and 'getenv +* Time Zone:: +@end menu -@defvar *modules* -Is a list of pathnames denoting files which have been loaded. -@end defvar -@defvar *catalog* -Is an association list of features (symbols) and pathnames which will -supply those features. The pathname can be either a string or a pair. -If pathname is a pair then the first element should be a macro feature -symbol, @code{source}, or @code{compiled}. The cdr of the pathname -should be either a string or a list. -@end defvar +@node Repl, Quick Print, Session Support, Session Support +@subsection Repl -In the following three functions if @var{feature} is not a symbol it is -assumed to be a pathname.@refill +@code{(require 'repl)} +@ftindex repl -@defun provided? feature -Returns @code{#t} if @var{feature} is a member of @code{*features*} or -@code{*modules*} or if @var{feature} is supported by a file already -loaded and @code{#f} otherwise.@refill -@end defun +Here is a read-eval-print-loop which, given an eval, evaluates forms. -@deffn Procedure require feature -If @code{(not (provided? @var{feature}))} it is loaded if @var{feature} -is a pathname or if @code{(assq @var{feature} *catalog*)}. Otherwise an -error is signaled.@refill +@deffn Procedure repl:top-level repl:eval +@code{read}s, @code{repl:eval}s and @code{write}s expressions from +@code{(current-input-port)} to @code{(current-output-port)} until an +end-of-file is encountered. @code{load}, @code{slib:eval}, +@code{slib:error}, and @code{repl:quit} dynamically bound during +@code{repl:top-level}.@refill @end deffn -@deffn Procedure provide feature -Assures that @var{feature} is contained in @code{*features*} if -@var{feature} is a symbol and @code{*modules*} otherwise.@refill +@deffn Procedure repl:quit +Exits from the invocation of @code{repl:top-level}. @end deffn -@defun require:feature->path feature -Returns @code{#t} if @var{feature} is a member of @code{*features*} or -@code{*modules*} or if @var{feature} is supported by a file already -loaded. Returns a path if one was found in @code{*catalog*} under the -feature name, and @code{#f} otherwise. The path can either be a string -suitable as an argument to load or a pair as described above for -*catalog*. -@end defun +The @code{repl:} procedures establish, as much as is possible to do +portably, a top level environment supporting macros. +@code{repl:top-level} uses @code{dynamic-wind} to catch error conditions +and interrupts. If your implementation supports this you are all set. -Below is a list of features that are automatically determined by -@code{require}. For each item, @code{(provided? '@var{feature})} will -return @code{#t} if that feature is available, and @code{#f} if -not.@refill +Otherwise, if there is some way your implementation can catch error +conditions and interrupts, then have them call @code{slib:error}. It +will display its arguments and reenter @code{repl:top-level}. +@code{slib:error} dynamically bound by @code{repl:top-level}.@refill -@itemize @bullet -@item -'inexact -@item -'rational -@item -'real -@item -'complex -@item -'bignum -@end itemize +To have your top level loop always use macros, add any interrupt +catching lines and the following lines to your Scheme init file: +@lisp +(require 'macro) +@ftindex macro +(require 'repl) +@ftindex repl +(repl:top-level macro:eval) +@end lisp +@node Quick Print, Debug, Repl, Session Support +@subsection Quick Print +@code{(require 'qp)} +@ftindex qp +@noindent +When displaying error messages and warnings, it is paramount that the +output generated for circular lists and large data structures be +limited. This section supplies a procedure to do this. It could be +much improved. +@quotation +Notice that the neccessity for truncating output eliminates +Common-Lisp's @xref{Format} from consideration; even when variables +@code{*print-level*} and @code{*print-level*} are set, huge strings and +bit-vectors are @emph{not} limited. +@end quotation -@node Vicinity, Configuration, Require, Session Support -@section Vicinity +@deffn Procedure qp arg1 @dots{} +@deffnx Procedure qpn arg1 @dots{} +@deffnx Procedure qpr arg1 @dots{} +@code{qp} writes its arguments, separated by spaces, to +@code{(current-output-port)}. @code{qp} compresses printing by +substituting @samp{...} for substructure it does not have sufficient +room to print. @code{qpn} is like @code{qp} but outputs a newline +before returning. @code{qpr} is like @code{qpn} except that it returns +its last argument.@refill +@end deffn -A vicinity is a descriptor for a place in the file system. Vicinities -hide from the programmer the concepts of host, volume, directory, and -version. Vicinities express only the concept of a file environment -where a file name can be resolved to a file in a system independent -manner. Vicinities can even be used on @dfn{flat} file systems (which -have no directory structure) by having the vicinity express constraints -on the file name. On most systems a vicinity would be a string. All of -these procedures are file system dependent. +@defvar *qp-width* +@code{*qp-width*} is the largest number of characters that @code{qp} +should use.@refill +@end defvar -These procedures are provided by all implementations. +@node Debug, Breakpoints, Quick Print, Session Support +@subsection Debug -@defun make-vicinity filename -Returns the vicinity of @var{filename} for use by @code{in-vicinity}. -@end defun +@code{(require 'debug)} +@ftindex debug -@defun program-vicinity -Returns the vicinity of the currently loading Scheme code. For an -interpreter this would be the directory containing source code. For a -compiled system (with multiple files) this would be the directory where -the object or executable files are. If no file is currently loading it -the result is undefined. @strong{Warning:} @code{program-vicinity} can -return incorrectl values if your program escapes back into a -@code{load}.@refill -@end defun +@noindent +Requiring @code{debug} automatically requires @code{trace} and +@code{break}. -@defun library-vicinity -Returns the vicinity of the shared Scheme library. -@end defun +@noindent +An application with its own datatypes may want to substitute its own +printer for @code{qp}. This example shows how to do this: -@defun implementation-vicinity -Returns the vicinity of the underlying Scheme implementation. This -vicinity will likely contain startup code and messages and a compiler. -@end defun +@example +(define qpn (lambda args) @dots{}) +(provide 'qp) +(require 'debug) +@ftindex debug +@end example -@defun user-vicinity -Returns the vicinity of the current directory of the user. On most -systems this is @file{""} (the empty string). -@end defun +@deffn Procedure trace-all file +Traces (@pxref{Trace}) all procedures @code{define}d at top-level in +file @file{file}. +@end deffn -@c @defun scheme-file-suffix -@c Returns the default filename suffix for scheme source files. On most -@c systems this is @samp{.scm}.@refill -@c @end defun +@deffn Procedure break-all file +Breakpoints (@pxref{Breakpoints}) all procedures @code{define}d at +top-level in file @file{file}. +@end deffn -@defun in-vicinity vicinity filename -Returns a filename suitable for use by @code{slib:load}, -@code{slib:load-source}, @code{slib:load-compiled}, -@code{open-input-file}, @code{open-output-file}, etc. The returned -filename is @var{filename} in @var{vicinity}. @code{in-vicinity} should -allow @var{filename} to override @var{vicinity} when @var{filename} is -an absolute pathname and @var{vicinity} is equal to the value of -@code{(user-vicinity)}. The behavior of @code{in-vicinity} when -@var{filename} is absolute and @var{vicinity} is not equal to the value -of @code{(user-vicinity)} is unspecified. For most systems -@code{in-vicinity} can be @code{string-append}.@refill -@end defun +@node Breakpoints, Trace, Debug, Session Support +@subsection Breakpoints -@defun sub-vicinity vicinity name -Returns the vicinity of @var{vicinity} restricted to @var{name}. This -is used for large systems where names of files in subsystems could -conflict. On systems with directory structure @code{sub-vicinity} will -return a pathname of the subdirectory @var{name} of -@var{vicinity}.@refill +@code{(require 'break)} +@ftindex break + +@defun init-debug +If your Scheme implementation does not support @code{break} or +@code{abort}, a message will appear when you @code{(require 'break)} or +@ftindex break +@code{(require 'debug)} telling you to type @code{(init-debug)}. This +@ftindex debug +is in order to establish a top-level continuation. Typing +@code{(init-debug)} at top level sets up a continuation for +@code{break}. @end defun +@defun breakpoint arg1 @dots{} +Returns from the top level continuation and pushes the continuation from +which it was called on a continuation stack. +@end defun +@defun continue +Pops the topmost continuation off of the continuation stack and returns +an unspecified value to it. +@defunx continue arg1 @dots{} +Pops the topmost continuation off of the continuation stack and returns +@var{arg1} @dots{} to it. +@end defun -@node Configuration, Input/Output, Vicinity, Session Support -@section Configuration - -These constants and procedures describe characteristics of the Scheme -and underlying operating system. They are provided by all -implementations. - -@defvr Constant char-code-limit -An integer 1 larger that the largest value which can be returned by -@code{char->integer}.@refill -@end defvr - -@defvr Constant most-positive-fixnum -The immediate integer closest to positive infinity. -@end defvr +@defmac break proc1 @dots{} +Redefines the top-level named procedures given as arguments so that +@code{breakpoint} is called before calling @var{proc1} @dots{}. +@defmacx break +With no arguments, makes sure that all the currently broken identifiers +are broken (even if those identifiers have been redefined) and returns a +list of the broken identifiers. +@end defmac -@defvr Constant slib:tab -The tab character. -@end defvr +@defmac unbreak proc1 @dots{} +Turns breakpoints off for its arguments. +@defmacx unbreak +With no arguments, unbreaks all currently broken identifiers and returns +a list of these formerly broken identifiers. +@end defmac -@defvr Constant slib:form-feed -The form-feed character. -@end defvr +The following routines are the procedures which actually do the tracing +when this module is supplied by SLIB, rather than natively. If +defmacros are not natively supported by your implementation, these might +be more convenient to use. -@defun software-type -Returns a symbol denoting the generic operating system type. For -instance, @code{unix}, @code{vms}, @code{macos}, @code{amiga}, or -@code{ms-dos}. +@defun breakf proc +@defunx breakf proc name +@defunx debug:breakf proc +@defunx debug:breakf proc name +To break, type +@lisp +(set! @var{symbol} (breakf @var{symbol})) +@end lisp +@noindent +or +@lisp +(set! @var{symbol} (breakf @var{symbol} '@var{symbol})) +@end lisp +@noindent +or +@lisp +(define @var{symbol} (breakf @var{function})) +@end lisp +@noindent +or +@lisp +(define @var{symbol} (breakf @var{function} '@var{symbol})) +@end lisp @end defun -@defun slib:report-version -Displays the versions of SLIB and the underlying Scheme implementation -and the name of the operating system. An unspecified value is returned. - -@example -(slib:report-version) @result{} slib "2a3" on scm "4e1" on unix -@end example +@defun unbreakf proc +@defunx debug:unbreakf proc +To unbreak, type +@lisp +(set! @var{symbol} (unbreakf @var{symbol})) +@end lisp @end defun -@defun slib:report -Displays the information of @code{(slib:report-version)} followed by -almost all the information neccessary for submitting a problem report. -An unspecified value is returned. +@node Trace, System Interface, Breakpoints, Session Support +@subsection Tracing -@defunx slib:report #t -provides a more verbose listing. +@code{(require 'trace)} +@ftindex trace -@defunx slib:report filename -Writes the report to file @file{filename}. +@defmac trace proc1 @dots{} +Traces the top-level named procedures given as arguments. +@defmacx trace +With no arguments, makes sure that all the currently traced identifiers +are traced (even if those identifiers have been redefined) and returns a +list of the traced identifiers. +@end defmac -@example -(slib:report) -@result{} -slib "2a3" on scm "4e1" on unix -(implementation-vicinity) is "/usr/local/src/scm/" -(library-vicinity) is "/usr/local/lib/slib/" -(scheme-file-suffix) is ".scm" -implementation *features* : - bignum complex real rational - inexact vicinity ed getenv - tmpnam system abort transcript - with-file ieee-p1178 rev4-report rev4-optional-procedures - hash object-hash delay eval - dynamic-wind multiarg-apply multiarg/and- logical - defmacro string-port source array-for-each - array full-continuation char-ready? line-i/o - i/o-extensions pipe -implementation *catalog* : - (rev4-optional-procedures . "/usr/local/lib/slib/sc4opt") - ... -@end example -@end defun +@defmac untrace proc1 @dots{} +Turns tracing off for its arguments. +@defmacx untrace +With no arguments, untraces all currently traced identifiers and returns +a list of these formerly traced identifiers. +@end defmac -@node Input/Output, Legacy, Configuration, Session Support -@section Input/Output +The following routines are the procedures which actually do the tracing +when this module is supplied by SLIB, rather than natively. If +defmacros are not natively supported by your implementation, these might +be more convenient to use. -These procedures are provided by all implementations. +@defun tracef proc +@defunx tracef proc name +@defunx debug:tracef proc +@defunx debug:tracef proc name +To trace, type +@lisp +(set! @var{symbol} (tracef @var{symbol})) +@end lisp +@noindent +or +@lisp +(set! @var{symbol} (tracef @var{symbol} '@var{symbol})) +@end lisp +@noindent +or +@lisp +(define @var{symbol} (tracef @var{function})) +@end lisp +@noindent +or +@lisp +(define @var{symbol} (tracef @var{function} '@var{symbol})) +@end lisp +@end defun -@deffn Procedure file-exists? filename -Returns @code{#t} if the specified file exists. Otherwise, returns -@code{#f}. If the underlying implementation does not support this -feature then @code{#f} is always returned. -@end deffn +@defun untracef proc +@defunx debug:untracef proc +To untrace, type +@lisp +(set! @var{symbol} (untracef @var{symbol})) +@end lisp +@end defun -@deffn Procedure delete-file filename -Deletes the file specified by @var{filename}. If @var{filename} can not -be deleted, @code{#f} is returned. Otherwise, @code{#t} is -returned.@refill -@end deffn -@deffn Procedure tmpnam -Returns a pathname for a file which will likely not be used by any other -process. Successive calls to @code{(tmpnam)} will return different -pathnames.@refill -@end deffn +@node System Interface, Time Zone, Trace, Session Support +@subsection System Interface -@deffn Procedure current-error-port -Returns the current port to which diagnostic and error output is -directed. -@end deffn +@noindent +If @code{(provided? 'getenv)}: -@deffn Procedure force-output -@deffnx Procedure force-output port -Forces any pending output on @var{port} to be delivered to the output -device and returns an unspecified value. The @var{port} argument may be -omitted, in which case it defaults to the value returned by -@code{(current-output-port)}.@refill -@end deffn +@defun getenv name +Looks up @var{name}, a string, in the program environment. If @var{name} is +found a string of its value is returned. Otherwise, @code{#f} is returned. +@end defun -@deffn Procedure output-port-width -@deffnx Procedure output-port-width port +@noindent +If @code{(provided? 'system)}: -Returns the width of @var{port}, which defaults to -@code{(current-output-port)} if absent. If the width cannot be -determined 79 is returned.@refill -@end deffn +@defun system command-string +Executes the @var{command-string} on the computer and returns the +integer status code. +@end defun -@deffn Procedure output-port-height -@deffnx Procedure output-port-height port +@noindent +If @code{(provided? 'current-time)}: -Returns the height of @var{port}, which defaults to -@code{(current-output-port)} if absent. If the height cannot be -determined 24 is returned.@refill -@end deffn +@noindent +The procedures @code{current-time}, @code{difftime}, and +@code{offset-time} deal with a @dfn{calendar time} datatype +@cindex time +@cindex calendar time +which may or may not be disjoint from other Scheme datatypes. -@node Legacy, System, Input/Output, Session Support -@section Legacy +@defun current-time +Returns the time since 00:00:00 GMT, January 1, 1970, measured in +seconds. Note that the reference time is different from the reference +time for @code{get-universal-time} in @ref{Common-Lisp Time}. +@end defun -@defun identity x -@var{identity} returns its argument. +@defun difftime caltime1 caltime0 +Returns the difference (number of seconds) between twe calendar times: +@var{caltime1} - @var{caltime0}. @var{caltime0} may also be a number. +@end defun -Example: -@lisp -(identity 3) - @result{} 3 -(identity '(foo bar)) - @result{} (foo bar) -(map identity @var{lst}) - @equiv{} (copy-list @var{lst}) -@end lisp +@defun offset-time caltime offset +Returns the calendar time of @var{caltime} offset by @var{offset} number +of seconds @code{(+ caltime offset)}. @end defun -These were present in Scheme until R4RS (@pxref{Notes, , Language -changes ,r4rs, Revised(4) Scheme}). +@node Time Zone, , System Interface, Session Support +@subsection Time Zone + +(require 'time-zone) + +@deftp {Data Format} TZ-string + +POSIX standards specify several formats for encoding time-zone rules. + +@table @t +@item :@i{} +If the first character of @i{} is @samp{/}, then +@i{} specifies the absolute pathname of a tzfile(5) format +time-zone file. Otherwise, @i{} is interpreted as a pathname +within @var{tzfile:vicinity} (/usr/lib/zoneinfo/) naming a tzfile(5) +format time-zone file. +@item @i{}@i{} +The string @i{} consists of 3 or more alphabetic characters. +@i{} specifies the time difference from GMT. The @i{} +is positive if the local time zone is west of the Prime Meridian and +negative if it is east. @i{} can be the number of hours or +hours and minutes (and optionally seconds) separated by @samp{:}. For +example, @code{-4:30}. +@item @i{}@i{}@i{} +@i{} is the at least 3 alphabetic characters naming the local +daylight-savings-time. +@item @i{}@i{}@i{}@i{} +@i{} specifies the offset from the Prime Meridian when +daylight-savings-time is in effect. +@end table -@defvr Constant t -Derfined as @code{#t}. -@end defvr +The non-tzfile formats can optionally be followed by transition times +specifying the day and time when a zone changes from standard to +daylight-savings and back again. + +@table @t +@item ,@i{}/@i{