stk/Doc/Reference/Reference2.tex

1722 lines
56 KiB
TeX

%
% STk Reference manual (Part 2)
%
% Author: Erick Gallesio [eg@unice.fr]
% Creation date: ??-Nov-1993 ??:??
% Last file update: 16-Aug-1999 20:21
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.11 Keywords
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Keywords}
\label{keywords}
Keywords are symbolic constants which evaluate to themselves. A keyword must
begin with a colon.
\begin{entry}{%
\proto{keyword?}{ obj}{procedure}}
\saut
Returns {\schtrue} if \var{obj} is a keyword, otherwise returns {\schfalse}.
\end{entry}
\begin{entry}{%
\proto{make-keyword}{ obj}{procedure}}
\saut
Builds a keyword from the given \var{obj}. \var{obj} must be a symbol
or a string. A colon is automatically prepended.
\begin{scheme}
(make-keyword "test") \lev :test
(make-keyword 'test) \lev :test
(make-keyword ":hello") \lev ::hello
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{keyword->string}{ keyword}{procedure}}
\saut
Returns the name of \var{keyword} as a string. The leading colon is
included in the result. %% axe: why this asymmetry ?
\begin{scheme}
(keyword->string :test) \lev ":test"
\end{scheme}
\end{entry}
%% axe: added description of list's format. (proposals for better
%% phrasing are welcome)
\begin{entry}{%
\proto{get-keyword}{ keyword list}{procedure}
\proto{get-keyword}{ keyword list default}{procedure}}
\saut
\var{List} must be a list of keywords and their respective values.
\ide{Get-keyword} scans the \var{list} and returns the value
associated with the given \var{keyword}. If the \var{keyword} does
not appear in an odd position in \var{list}, the specified
\var{default} is returned, or an error is raised if no default was
specified.
\begin{scheme}
(get-keyword :one '(:one 1 :two 2)) \lev 1
(get-keyword :four '(:one 1 :two 2) \schfalse) \lev \schfalse
(get-keyword :four '(:one 1 :two 2)) \lev \scherror
\end{scheme}
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.12: Tk commands
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Tk commands}
\label{tkcommand}
As we mentioned in the introduction, {\stk} can easily communicate
with the Tk toolkit\index{Tk toolkit}\index{toolkit}. All the commands
defined by the Tk toolkit are visible as \ide{Tk-command}s, a basic
type recognized by the interpreter. \ide{Tk-command}s can be called
like regular scheme procedures, serving as an entry point into the Tk
library.
%
\vskip3mm
\begin{note}
Some \ide{Tk-command}s can dynamically create other
\ide{Tk-command}s. For instance, execution of the expression
\begin{scheme}
(label '.lab)
\end{scheme} %
will create a new \ide{Tk-command} called ``\var{.lab}''. This new
object, which was created by a primitive \ide{Tk-command}, will be
called a \var{widget}\index{widget}.
\end{note}
\begin{note}
When a new widget is created, it captures its creation environment. This
permits to have bindings which access variables in the scope of the widget
creation call (see \ref{addresses}). %% ??
\end{note}
\begin{entry}{%
\proto{tk-command?}{ obj}{procedure}}
\saut
Returns {\schtrue} if \var{obj} is a \ide{Tk-command}, otherwise
returns {\schfalse}.
\begin{scheme}
(tk-command? label) \lev {\schtrue}
(begin (label '.lab) (tk-command? .lab)) \lev {\schtrue}
(tk-command? 12) \lev {\schfalse}
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{widget?}{ obj}{procedure}}
\saut
Returns {\schtrue} if \var{obj} is a widget, otherwise returns
{\schfalse}. A widget is a \ide{Tk-command} created by a primitive
\ide{Tk-command} such as \ide{button}, \ide{label}, \ide{menu}, etc.
\begin{scheme}
(widget? label) \lev {\schfalse}
(begin (label '.lab) (widget? .lab)) \lev {\schtrue}
(widget? 12) \lev {\schfalse}
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{widget->string}{ widget}{procedure}}
\saut
Returns the widget name of \var{widget} as a string.
\begin{scheme}
(begin (label '.lab) (widget->string .lab)) \lev ".lab"
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{string->widget}{ str}{procedure}}
\saut
Returns the widget whose name is \var{str} if it exists; otherwise
returns {\schfalse}.
\begin{scheme}
(begin (label '.lab) (string->widget ".lab")) \lev the \ide{Tk-command} named ".lab"
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{widget-name}{ widget}{procedure}}
\saut
Returns the widget name of \var{widget} as a symbol.
\begin{scheme}
(begin (label '.lab) (widget->name .lab)) \lev .lab
\end{scheme}
\end{entry}
\begin{entry}{
\proto{set-widget-data!}{ widget expr}{procedure}}
\saut
%
\ide{Set-widget-data!} associates arbitrary data with a \var{widget}.
The system makes no assumptions about the type of {\tt expr}; the data
is for programmer convenience only. As shown below, it could be used
as a kind of property list for widgets.
\end{entry}
\begin{entry}{
\proto{get-widget-data}{ widget}{procedure}}
\saut
Returns the data previously associated with \var{widget} if it exists;
otherwise returns {\schfalse}.
\begin{scheme}
(begin
(set-widget-data! .w '(:mapped {\schtrue} :geometry "10x50"))
(get-keyword :mapped (get-widget-data .w))) \lev {\schtrue}
\end{scheme}
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.13: Modules
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Modules}
\label{module}
{\stk} modules can be used to organize a program into separate
environments (or\textit{name spaces}). Modules provide a clean way to
organize and enforce the barriers between the components of a program.
{\stk} provides a simple module system which is largely inspired from
the one of Tung and Dybvig exposed in \cite{Tung-Dybvig-96}. As their
modules system, {\stk} modules are defined to be easily used in an
interactive environment.
\begin{entry}{%
\proto{define-module}{ name \hyper{body}} {syntax}}
\saut
\var{Define-module} evaluates the expressions which are in
\hyper{body} in the environment of the module \var{name}. \var{name}
must be a valid symbol. If this symbol has not already been used to
define a module, a new module, named \var{name}, is created.
Otherwise, \hyper{body} is evaluated in the environment of the (old)
module \var{name}\footnote{ In fact {\tt define-module} on a given name
defines a new module only the first time it is invoked on this name.
By this way, inteactively reloading a module does not define a new entity,
and the other modules which use it are not altered.}.
Definitions done in a module are local to the module and do not interact with
the definitions of other modules. Consider the following definitions,
\begin{scheme}
(define-module M1
(define a 1))
(define-module M2
(define a 2)
(define b (* 2 x)))
\end{scheme}
Here, two modules are defined and they both bind the symbol \texttt{a} to a
value. However, since \texttt{a} has been defined in two distincts modules
they denote two different locations.
The ``\texttt{STk}'' module, which is predefined, is a special module
which contains all the \textit{global variables} of a {\rrrr} program.
A symbol defined in the \texttt{STk} module, if not hidden by a local
definition, is always visible from inside a module. So, in the
previous exemple, the \texttt{x} symbol refers the \texttt{x} symbol
defined in the \texttt{STk} module.
The result of \var{define-module} is undefined.
\end{entry}
\begin{entry}{%
\proto{find-module}{ name} {procedure}
\proto{find-module}{ name default} {procedure}}
\saut
{\stk} modules are first class objects and \ide{find-module} returns the
module associated to \var{name} if it exists. If there is no module
associated to \var{name}, an error is signaled if no \var{default} is
provided, otherwise \ide{find-module} returns default.
\end{entry}
\begin{entry}{%
\proto{module?}{ object} {procedure}}
\saut
Returns {\schtrue} if \var{object} is a module and {\schfalse} otherwise.
\begin{scheme}
(module? (find-module 'STk)) \lev \schtrue
(module? 'STk) \lev \schfalse
(module? 1) \lev \schfalse
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{export}{ \hyperi{symbol} \hyperii{symbol}\ldots} {syntax}}
\saut
Specifies the symbols which are exported (i.e. \textit{visible}) outside
the current module. By default, symbols defined in a module are not
visible outside this module, excepted the symbols which appear in an
\texttt{export} clause.
If several \texttt{export} clauses appear in a module, the set of
exported symbols is determined by {\em unioning} symbols exported
in all the \texttt{export} clauses.
The result of \var{export} is undefined.
\end{entry}
\begin{entry}{%
\proto{import}{ \hyperi{module} \hyperii{module}\ldots} {syntax}}
\saut
Specifies the modules which are imported by the current module.
Importing a module makes the symbols it exports visible to the
importer, if not hidden by local definitions. When a symbol
is exported by several of the imported modules, the location denoted by
this symbol in the importer module correspond to the one of the first module
in the list (\hyperi{module} \hyperii{module}\ldots) which export it.
If several \texttt{import} clauses appear in a module, the set of
imported modules is determined by appending the various list of modules
in their apparition order.
\begin{scheme}
(define-module M1
(export a b)
(define a 'M1-a)
(define b 'M1-b))
(define-module M2
(export b c)
(define b 'M2-b)
(define c 'M2-c))
(define-module M3
(import M1 M2)
(display (list a b c))) \lev displays (m1-a m1-b m2-c)
\end{scheme}
\begin{note}
There is no kind of \emph{transitivity} in module importations: when
the module $C$ imports the module $B$ which an importer of $A$, the
symbols of $A$ are not visible from $C$, except by explicitly
importing the $A$ module from $C$.
\end{note}
\begin{note}
The module \texttt{STk}, which contains the \textit{global
variables} is always implicitly imported from a
module.Furthermore, this module is always placed at the end of the
list of imported modules.
\end{note}
\end{entry}
\begin{entry}{%
\proto{export-symbol}{ symbol module} {procedure}}
\saut
Exports \var{symbol} from \var{module}. This procedure can be useful, when
debugging a program, to make visible a given symbol without reloading
or redefining the module where this symbol was defined.
\end{entry}
\begin{entry}{%
\proto{export-all-symbols}{} {procedure}}
\saut
Exports all the symbols of current module . If symbols are added to
the current \var{module} after the call to \ide{export-all-symbols},
they are automatically exported.
\begin{note}
The \texttt{STk} module export all the symbols which are defined in
it (i.e. \textit{global variables} are visible, if not hidden, from
all the modules of a program.
\end{note}
\end{entry}
\begin{entry}{%
\proto{with-module}{ name \hyperi{expr} \hyperii{expr} \ldots} {syntax}}
\saut
Evaluates the expressions of \hyperi{expr} \hyperii{expr} \ldots in
the environment of module \var{name}. Module \var{name} must have been created
previously by a \ide{define-module}. The result of \ide{with-module}
is the result of the evaluation of the last \hyper{expr}.
\begin{scheme}
(define-module M
(define a 1)
(define b 2))
(with-module M
(+ a b)) \lev 3
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{current-module}{} {procedure}}
\saut
Returns the current-module.
\begin{scheme}
(define-module M
...)
(with-module M
(cons (eq? (current-module) (find-module 'M))
(eq? (current-module) (find-module 'STk))))
\lev (\schtrue . \schfalse)
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{select-module}{ name} {syntax}}
\saut
Evaluates the expressions which follows in module \var{name}
environment. Module \var{name} must have been created previously by a
\ide{define-module}. The result of \ide{select-module} is undefined.
\ide{Select-module} is particularly useful when debugging since it
allows to place toplevel evaluation in a particular module. The
following transcript shows an usage of
\ide{select-module}\footnote{This transcript uses the default value for the
function \texttt{repl-display-prompt} (see page \pageref{repl-display-prompt})
which displays the name of the current module in the prompt.}:
\begin{scheme}
STk> (define foo 1)
STk> (define-module bar
(define foo 2))
STk> foo
1
STk> (select-module bar)
bar> foo
2
bar> (select-module STk)
STk>
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{module-name}{ module} {procedure}}
\saut
Returns the name (a symbol) associated to a \var{module}.
\end{entry}
\begin{entry}{%
\proto{module-imports}{ module} {procedure}}
\saut
Returns the list modules that \var{module} imports.
\end{entry}
\begin{entry}{%
\proto{module-exports}{ module} {procedure}}
\saut
Returns the list of symbols exported by \var{module}.
\end{entry}
\begin{entry}{%
\proto{module-symbols}{ module} {procedure}}
\saut
Returns the list symbols that ere defined in \var{module}.
\end{entry}
\begin{entry}{%
\proto{all-modules}{ } {procedure}}
\saut
Returns a list of all the living modules.
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.13: Environments
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Environments}
\label{environment}
Environments are first class objects in STk. The following primitives
are defined on environments.
\begin{entry}{%
\proto{environment?}{ obj} {procedure}}
\saut
Returns {\schtrue} if \var{obj} is an environment, otherwise returns
{\schfalse}.
\end{entry}
\begin{entry}{%
\proto{the-environment} {} {procedure}}
\saut
Returns the current environment.
\end{entry}
\begin{entry}{%
\proto{global-environment} {} {procedure}}
\saut
Returns the ``global'' environment (i.e. the toplevel environment).
\mainindex{top level environment}
\end{entry}
\begin{entry}{%
\proto{parent-environment} { env} {procedure}}
\saut
Returns the parent environment of \var{env}. If env is the ``global''
environment (i.e. the toplevel environment), \ide{parent-environment}
returns {\schfalse}.
\end{entry}
\begin{entry}{%
\proto{environment->list}{ environment} {procedure}}
\saut
Returns a list of {\em a-lists}, representing the bindings in
\var{environment}. Each {\em a-list} describes one level of bindings,
with the innermost level coming first.
\begin{scheme}
(define E (let ((a 1) (b 2))
(let ((c 3))
(the-environment))))
(car (environment->list E)) \ev ((c . 3))
(cadr (environment->list E)) \ev ((b . 2) (a . 1))
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{procedure-environment}{ procedure} {procedure}}
\saut
Returns the environment associated with \var{procedure}.
\ide{Procedure-environment} returns {\schfalse} if \var{procedure}
is not a closure.
\begin{scheme}
(define foo (let ((a 1)) (lambda () a)))
(car (environment->list
(procedure-environment foo)))
\ev ((a . 1))
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{module-environment}{ module} {procedure}}
\saut
Returns the environment associated to the module \var{module}.
\begin{scheme}
(define-module M
(define a 1))
(car (environment->list
(module-environment (find-module 'M))))
\ev ((a . 1))
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{symbol-bound?}{ symbol}{procedure}
\proto{symbol-bound?}{ symbol environment}{procedure}}
\saut
Returns {\schtrue} if \var{symbol} has a value in the given
\var{environment}, otherwise returns {\schfalse}. \var{Environment}
may be omitted, in which case it defaults to the global environment.
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.14: Macros
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Macros}
\label{macros}
{\stk} provides low level macros.
\begin{note}
{\stk} macros are not the sort of macros defined in the appendix of {\rrrr},
but rather the macros one can find in most of Lisp dialects.
\end{note}
\begin{entry}{%
\proto{macro}{ \hyper{formals} \hyper{body}}{\exprtype}}
\saut
{\tt Macro} permits to create a macro. When a macro is called, the whole form
(i.e. the macro itself and its parameters) is passed to the macro body.
Binding association is done in the environment of the call. The result of the
binding association is called the {\em macro-expansion}\index{macro-expansion}.
The result of the macro call is the result of the evaluation of the
macro expansion in the call environment.
%% FIXME: This needs rephrasing...
\begin{scheme}
(define foo (macro f `(quote ,f)))
(foo 1 2 3) \ev (foo 1 2 3)
(define 1+ (macro form (list + (cadr form) 1)))
(let ((x 1)) (1+ x)) \ev 2
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{macro?}{ obj}{procedure}}
\saut
Returns {\schtrue} if \var{obj} is a macro, otherwise returns {\schfalse}.
\end{entry}
\begin{entry}{%
\proto{macro-expand-1}{ form}{procedure}
\proto{macro-expand}{ form}{procedure}}
\saut
\ide{Macro-expand-1} returns the macro expansion of \var{form} if
it is a macro call, otherwise \var{form} is returned unchanged.
\ide{Macro-expand} is similar to \ide{macro-expand-1}, but repeately
expand \var{form} until it is no longer a macro call.
\begin{scheme}
(define 1- (macro form `(- ,(cadr form) 1)))
(define -- (macro form `(1- ,(cadr form))))
(macro-expand-1 '(1- 10)) \ev (- 10 1)
(macro-expand '(1- 10)) \ev (- 10 1)
(macro-expand-1 '(-- 10)) \ev (1- 10)
(macro-expand '(-- 10)) \ev (- 10 1)
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{macro-expand}{ form}{procedure}}
\saut
Returns the macro expansion of \var{form} if it is a macro call, otherwise
\var{form} is returned unchanged. Macro expansion continue until, the form
obtained is
\begin{scheme}
(define 1- (macro form (list '- (cadr form) 1)))
(macro-expand '(1- 10)) \ev (- 10 1)
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{macro-body}{ macro}{procedure}}
\saut
Returns the body of \var{macro}
\begin{scheme}
(macro-body 1+)
\ev (macro form (list + (cadr form) 1))
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{define-macro}{ (\hyper{name} \hyper{formals}) \hyper{body}}{macro}}
\saut
\ide{Define-macro} is a macro which permits to define a macro more easily than
with the \ide{macro} form. It is similar to the {\tt defmacro} of Common
Lisp~\cite{CLtL2}.
\begin{scheme}
(define-macro (incr x) `(set! ,x (+ ,x 1)))
(let ((a 1)) (incr a) a) \ev 2
(define-macro (when test . body)
`(if ,test ,@(if (null? (cdr body)) body `((begin ,@body)))))
(macro-expand '(when a b)) \ev (if a b)
(macro-expand '(when a b c d))
\ev (if a (begin b c d))
\end{scheme}
\begin{note}
Calls to macros defined by \ide{define-macro} are physically replaced by their
macro-expansion if the variable \ide{*debug*} is {\schfalse} (i.e. their body
is ``in-lined'' in the macro call). To avoid this
feature, and to ease debugging, you have to set this variable to {\schtrue}.
(See also \ref{uncode}).
\end{note}
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.15: System procedures
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{System procedures}
This section lists a set of procedures which permits to access some system
internals.
\begin{entry}{%
\proto{expand-file-name}{ string} {procedure}}
\saut
\ide{Expand-file-name} expands the filename given in \var{string} to
an absolute path. This function understands the {\em tilde
convention}\index{tilde expansion} for filenames.
\begin{scheme}
;; Current directory is /users/eg/STk
(expand-file-name "..") \lev "/users/eg"
(expand-file-name "{\tilda}root/bin) \lev "/bin"
(expand-file-name "{\tilda}/STk)" \lev "/users/eg/STk"
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{canonical-path}{ path} {procedure}}
\saut
Expands all symbolic links in \var{path} and returns its canonicalized
absolute pathname. The resulting path do not have symbolic links. If
\var{path} doesn't designate a valid pathname, \var{canonical-path} returns
\schfalse.
\end{entry}
\begin{entry}{%
\proto{dirname}{ string} {procedure}}
\saut
Returns a string containing all but the last component of the path name given in
\var{string}.
\begin{scheme}
(dirname "/a/b/c.stk") \lev "/a/b"
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{basename}{ string} {procedure}}
\saut
Returns a string containing the last component of the path name given in
\var{string}.
\begin{scheme}
(basname "/a/b/c.stk") \lev "c.stk"
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{decompose-file-name}{ string} {procedure}}
\saut
Returns an ``exploded'' list of the path name components given in
\var{string}.
The first element in the list denotes if the given \var{string} is an
absolute path or a relative one, being {\tt "/"} or {\tt "."} respectively.
Each component of this list is a string.
\begin{scheme}
(decompose-file-name "/a/b/c.stk") \lev ("/" "a" "b" "c.stk")
(decompose-file-name "a/b/c.stk") \lev ("." "a" "b" "c.stk")
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{file-is-directory?}{ string} {procedure}
\proto{file-is-regular?}{ string} {procedure}
\proto{file-is-readable?}{ string} {procedure}
\proto{file-is-writable?}{ string} {procedure}
\proto{file-is-executable?}{ string} {procedure}
\proto{file-exists?}{ string} {procedure}}
\saut
Returns {\schtrue} if the predicate is true for the path name given in
\var{string}; returns {\schfalse} otherwise (or if \var{string} denotes a file
which does not exist).
\end{entry}
\begin{entry}{%
\proto{glob}{ \vri{pattern} \vrii{pattern} \dotsfoo} {procedure}}
\saut
The code for \ide{glob} is taken from the Tcl library. It performs
file name ``globbing'' in a fashion similar to the csh shell.
\ide{Glob} returns a list of the filenames that match at least one of
the {\em pattern} arguments. The \var{pattern} arguments may contain
the following special characters:
\begin{itemize}
\item ? Matches any single character.
\item \etoile~Matches any sequence of zero or more characters.
\item {\leftbracket}chars\rightbracket~Matches any single character in chars.
If chars contains a sequence of the form {\tt a-b} then any character between
{\tt a} and {\tt b} (inclusive) will match.
\item \verb+\+x Matches the character {\tt x}.
\item \{a,b,...\} Matches any of the strings {\tt a}, {\tt b}, etc.
\end{itemize}
As with csh, a ``.'' at the beginning of a file's name or just after a ``/''
must be matched explicitly or with a \{\} construct. In addition, all ``/''
characters must be matched explicitly.
If the first character in a pattern is ``{\tilda}'' then it refers to
the home directory of the user whose name follows the ``{\tilda}''.
If the ``{\tilda}'' is followed immediately by ``/'' then the value of
the environment variable HOME is used.
\ide{Glob} differs from csh globbing in two ways. First, it does not
sort its result list (use the \ide{sort} procedure if you want the list sorted).
Second, glob only returns the names of files that actually exist; in csh no
check for existence is made unless a pattern contains a ?, \etoile, or
\leftbracket\rightbracket
construct.
\end{entry}
\begin{entry}{%
\proto{remove-file}{ string} {procedure}}
\saut
Removes the file whose path name is given in \var{string}.
The result of \ide{remove-file} is undefined.
\end{entry}
\begin{entry}{%
\proto{rename-file}{ \vri{string} \vrii{string}} {procedure}}
\saut
Renames the file whose path-name is contained in \vri{string} in the path
name given by \vrii{string}. The result of \ide{rename-file} is undefined.
\end{entry}
\begin{entry}{%
\proto{temporary-file-name}{ string} {procedure}}
\saut
Generates a unique temporary file name. The value returned by
\ide{temporary-file-name} is the newly generated name of {\schfalse}
if a unique name cannot be generated.
\end{entry}
\begin{entry}{%
\proto{getcwd}{} {procedure}}
\saut
\ide{Getcwd} returns a string containing the current working directory.
\end{entry}
\begin{entry}{%
\proto{chdir}{ string} {procedure}}
\saut
\ide{Chdir} changes the current directory to the directory given in
\var{string}.
\end{entry}
\begin{entry}{%
\proto{getpid}{ string} {procedure}}
\saut
Returns the system process number of the current {\stk} interpreter (i.e. the
Unix {\em pid}). Result is an integer.
\end{entry}
\begin{entry}{%
\proto{system}{ string} {procedure}
\proto{!}{ string} {procedure}}
\saut
Sends the given \var{string} to the system shell \var{/bin/sh}. The result of
\ide{system} is the integer status code the shell returns.
\end{entry}
\begin{entry}{%
\proto{exec}{ string} {procedure}}
\saut
Executes the command contained in \var{string} and redirects its output in
a string. This string constitutes the result of \ide{exec}.
\end{entry}
\begin{entry}{%
\proto{getenv}{ string} {procedure}}
\saut
Looks for the environment variable named \var{string} and returns its
value as a string, if it exists. Otherwise, \ide{getenv} returns
{\schfalse}.
\begin{scheme}
(getenv "SHELL") \lev "/bin/zsh"
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{setenv!}{ var value} {procedure}}
\saut
Sets the environment variable \var{var} to \var{value}. \var{Var} and
\var{value} must be strings. The result of {\tt setenv!} is undefined.
\begin{scheme}
(getenv "SHELL") \lev "/bin/zsh"
\end{scheme}
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.16: Addresses
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Addresses}
\label{addresses}
An {\em address} is a Scheme object which contains a reference to
another Scheme object. This type can be viewed as a kind of pointer to
a Scheme object. Addresses, even though they are very dangerous, have
been introduced in {\stk} so that objects that have no ``readable''
external representation can still be transformed into strings and back
without loss of information. Adresses were useful with pre-3.0 version
of {\stk}; their usage is now {\bf stongly discouraged}, unless you know what you
do. In particular, an address can designate an object at a time and
another one later (i.e. after the garbage collector has marked the zone
as free).
Addresses are printed with a special syntax: {\tt {\sharpsign}pNNN},
where {\tt NNN} is an hexadecimal value. Reading this value back
yields the original object whose location is {\tt NNN}.
\begin{entry}{%
\proto{address-of}{ obj} {procedure}}
\saut
Returns the address of \ide{obj}.
\end{entry}
\begin{entry}{%
\proto{address?}{ obj} {procedure}}
\saut
Returns {\schtrue} if \var{obj} is an address; returns {\schfalse} otherwise.
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.17: Signals
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Signals}
\label{signals}
{\stk} allows the use to associate handlers to signals. Signal
handlers for a given signal can even be chained in a list. When a
signal occurs, the first signal of the list is executed. Unless this
signal yields the symbol \ide{break} the next signal of the list is
evaluated. When a signal handler is called, the integer value of this
signal is passed to it as (the only) parameter.
The following POXIX.1\mainindex{POSIX.1} constants for signal numbers
are defined: \ide{SIGABRT}, \ide{SIGALRM}, \ide{SIGFPE}, \ide{SIGHUP},
\ide{SIGILL}, \ide{SIGINT}, \ide{SIGKILL}, \ide{SIGPIPE}, {\tt
SIGQUIT}, \ide{SIGSEGV}, \ide{SIGTERM}, \ide{SIGUSR1}, {\tt
SIGUSR2}, \ide{SIGCHLD}, \ide{SIGCONT}, \ide{SIGSTOP}, {\tt
SIGTSTP}, \ide{SIGTTIN}, \ide{SIGTTOU}. Moreover, the following
constants, which are often available on most systems are also
defined\footnote{Some of these constants may be undefined if they are
not supported by your system}: \ide{SIGTRAP}, \ide{SIGIOT}, {\tt
SIGEMT}, \ide{SIGBUS}, \ide{SIGSYS}, \ide{SIGURG}, \ide{SIGCLD},
\ide{SIGIO}, \ide{SIGPOLL}, \ide{SIGXCPU}, \ide{SIGXFSZ}, {\tt
SIGVTALRM}, \ide{SIGPROF}, \ide{SIGWINCH}, \ide{SIGLOST}.
See your Unix documentation for the exact meaning of each constant or
\cite{Posix.1-90}. Use symbolic constants rather than their numeric
value if you plan to port your program on another system.
\label{GCSTART}
A special signal, managed by the interpreter, is also defined: {\tt
SIGHADGC}. This signal is raised when the garbage collector phase
terminates.
When the interpreter starts running, all signals are sets to their
default value, excepted \ide{SIGINT} (generally bound to {\ide
Control-C}) which is handled specially.
\begin{entry}{%
\proto{set-signal-handler!}{ sig handler} {procedure}}
\saut
Replace the handler for signal \var{sig} with \var{handler}.
Handler can be
\begin{itemize}
\item [-] {\schtrue} to reset the signal handler for \var{sig} to the
default system handler.
\item [-] {\schfalse} to completly ignore \var{sig} (Note that
Posix.1 states that \ide{SIGKILL} and \ide{SIGSTOP} cannot be caught
or ignored).
\item [-] a one parameter procedure.
\end{itemize}
This procedure returns the new handler, or (length 1) handler list,
associated to \var{sig}.
\begin{scheme}
(let* ((x \schfalse)
(handler (lambda (i) (set! x \schtrue))))
(set-signal-handler! |SIGHADGC| handler)
(gc)
x) \lev \schtrue
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{add-signal-handler!}{ sig handler} {procedure}}
\saut
Adds \var{handler} to the list of handlers for signal \var{sig}. If
the old signal handler is a boolean, this procedure is equivalent to
\ide{set-signal-handler!}. Otherwise, the new handler is added in
front of the previous list of handler. This procedure returns the new
handler, or handler list, associated to \var{sig}.
\begin{scheme}
(let* ((x '())
(handler1 (lambda (i) (set! x (cons 1 x))))
(handler2 (lambda (i) (set! x (cons 2 x)))))
(add-signal-handler! |SIGHADGC| handler1)
(add-signal-handler! |SIGHADGC| handler2)
(gc)
x) \lev (1 2)
\end{scheme}
\saut
\begin{scheme}
(let* ((x '())
(handler1 (lambda (i) (set! x (cons 1 x))))
(handler2 (lambda (i) (set! x (cons 2 x)) 'break)))
(add-signal-handler! |SIGHADGC| handler1)
(add-signal-handler! |SIGHADGC| handler2)
(gc)
x) \lev (2)
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{get-signal-handlers}{} {procedure}
\proto{get-signal-handlers}{ sig} {procedure}}
\saut
Returns the handlers, or the list of handlers, associated to the signal
\var{sig}. If \var{sig} is omitted, \ide{get-signal-handlers} returns
a vector of all the signal handlers currently in effect.
\end{entry}
\begin{entry}{%
\proto{send-signal}{ sig} {procedure}}
\saut
Sends the signal \var{sig} to the running program.
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.18: Hash tables
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Hash tables}
\label{hashtables}
A hash table consists of zero or more entries, each consisting of a key and a
value. Given the key for an entry, the hashing function can very quickly
locate the entry, and hence the corresponding value. There may be at most one
entry in a hash table with a particular key, but many entries may have the
same value.
{\stk} hash tables grow gracefully as the number of entries increases, so that
there are always less than three entries per hash bucket, on average. This
allows for fast lookups regardless of the number of entries in a table.
\vskip3mm
\begin{note}
Hash table manipulation procedures are built upon the efficient Tcl hash
table package.
\end{note}
\begin{entry}{
\proto{make-hash-table}{}{ procedure}
\proto{make-hash-table}{ comparison}{ procedure}
\proto{make-hash-table}{ comparison hash}{ procedure}}
\saut
\ide{Make-hash-table} admits three different forms.
The most general form admit two arguments. The first argument is a
comparison function which determine how keys are compared; the second
argument is a function which computes a hash code for an object and
returns the hash code as a non negative integer. Objets with the same
hash code are stored in an A-list registered in the bucket
corresponding to the key.
If omitted,
\begin{itemize}
\item {\tt hash} defaults to the \ide{hash-table-hash}
procedure.
\item {\tt comparison } defaults to the \ide{eq?} procedure
\end{itemize}
Consequently,
\begin{scheme}
(define h (make-hash-table))
\end{scheme}
is equivalent to
\begin{scheme}
(define h (make-hash-table eq? hash-table-hash))
\end{scheme}
Another interesting example is
\begin{scheme}
(define h (make-hash-table string-ci=? string-length))
\end{scheme}
which defines a new hash table which uses {\tt string-ci=?} for
comparing keys. Here, we use the string-length as a (very simple)
hashing function. Of course, a function which gives a key depending
of the characters composing the string gives a better repartition
and should probably enhance performances. For instance, the following
call to {\tt make-hash-table} should return a more efficient, even if
not perfect, hash table:
\begin{scheme}
(make-hash-table
string-ci=?
(lambda (s)
(let ((len (string-length s)))
(do ((h 0) (i 0 (+ i 1)))
((= i len) h)
(set! h (+ h (char->integer
(char-downcase (string-ref s i)))))))))
\end{scheme}
\begin{note}
Hash tables with a comparison function equal to \ide{eq?} or {\tt
string=?} are handled in an more efficient way (in fact, they
don't use the \ide{hash-table-hash} fucntion to speed up hash table
retrievals).
\end{note}
\end{entry}
\begin{entry}{
\proto{hash-table?}{ obj}{ procedure}}
\saut
Returns {\schtrue} if \var{obj} is a hash table, returns {\schfalse} otherwise.
\end{entry}
\begin{entry}{
\proto{hash-table-hash}{ obj}{ procedure}}
\saut
\ide{hash-table-hash} computes a hash code for an object and returns
the hash code as a non negative integer. A property of {\tt
hash-table-hash} is that
\begin{quote}
{\tt (equal? x y)} implies {\tt (equal? (hash-table-hash x) (hash-table-hash y)}
\end{quote}
as the the Common Lisp {\tt sxhash} function from which this procedure is
modeled.
\end{entry}
\begin{entry}{
\proto{hash-table-put!}{ hash key value}{ procedure}}
\saut
\ide{Hash-table-put!} enters an association between \var{key} and \var{value} in the
\var{hash} table. The value returned by \ide{hash-table-put!} is undefined.
\end{entry}
\begin{entry}{
\proto{hash-table-get}{ hash key}{ procedure}
\proto{hash-table-get}{ hash key default}{ procedure}}
\saut
\ide{Hash-table-get} returns the value associated with \var{key} in
the given \var{hash} table. If no value has been associated with \var{key} in
\var{hash}, the specified \var{default} is returned if given; otherwise an
error is raised.
\begin{scheme}
(define h1 (make-hash-table))
(hash-table-put! h1 'foo (list 1 2 3))
(hash-table-get h1 'foo) \lev (1 2 3)
(hash-table-get h1 'bar 'absent) \lev absent
(hash-table-get h1 'bar) \lev \scherror
(hash-table-put! h1 '(a b c) 'present)
(hash-table-get h1 '(a b c) 'absent) \lev 'absent
(define h2 (make-hash-table equal?))
(hash-table-put! h2 '(a b c) 'present)
(hash-table-get h2 '(a b c)) \lev 'present
\end{scheme}
\end{entry}
\begin{entry}{
\proto{hash-table-remove!}{ hash key}{ procedure}}
\saut
\var{hash} must be a hash table containing an entry for \var{key}.
\ide{Hash-table-remove!} deletes the entry for \var{key} in
\var{hash}, if it exists. Result of {\tt Hash-table-remove!} is unspecified.
\begin{scheme}
(define h (make-hash-table))
(hash-table-put! h 'foo (list 1 2 3))
(hash-table-get h 'foo) \lev (1 2 3)
(hash-table-remove! h 'foo)
(hash-table-get h 'foo 'absent) \lev absent
\end{scheme}
\end{entry}
\begin{entry}{
\proto{hash-table-for-each}{ hash proc}{procedure}}
\saut %
\var{Proc} must be a procedure taking two arguments.
\ide{Hash-table-for-each} calls \var{proc} on each key/value
association in \var{hash}, with the key as the first argument and the
value as the second. The value returned by \ide{hash-table-for-each}
is undefined.
\vskip3mm
\begin{note}
The order of application of \var{proc} is unspecified.
\end{note}
\begin{scheme}
(let ((h (make-hash-table))
(sum 0))
(hash-table-put! h 'foo 2)
(hash-table-put! h 'bar 3)
(hash-table-for-each h (lambda (key value)
(set! sum (+ sum value))))
sum) \lev 5
\end{scheme}
\end{entry}
\begin{entry}{
\proto{hash-table-map}{ hash proc}{procedure}}
\saut %
\var{Proc} must be a procedure taking two arguments.
\ide{Hash-table-map} calls \var{proc} on each entry in \var{hash},
with the entry's key as the first argument and the entry's value as
the second. The result of \ide{hash-table-map} is a list of the
values returned by \var{proc}, in unspecified order. %
\vskip3mm
\begin{note}
The order of application of \var{proc} is unspecified.
\end{note}
\begin{scheme}
(let ((h (make-hash-table)))
(dotimes (i 5)
(hash-table-put! h i (number->string i)))
(hash-table-map h (lambda (key value)
(cons key value)))) \lev ((0 . "0") (3 . "3") (2 . "2") (1 . "1") (4 . "4"))
\end{scheme}
\end{entry}
\begin{entry}{
\proto{hash-table->list}{ hash}{ procedure}}
\saut %
\ide{hash-table->list} returns an ``association list'' built from the
entries in \var{hash}. Each entry in \var{hash} will be represented
as a pair whose \var{car} is the entry's key and whose \var{cdr} is
its value.
\begin{note}
The order of pairs in the resulting list is unspecified.
\end{note}
\begin{scheme}
(let ((h (make-hash-table)))
(dotimes (i 5)
(hash-table-put! h i (number->string i)))
(hash-table->list h)) \lev ((0 . "0") (3 . "3") (2 . "2") (1 . "1") (4 . "4"))
\end{scheme}
\end{entry}
\begin{entry}{
\proto{hash-table-stats}{ hash}{procedure}}
\saut %
\ide{Hash-table-stats} returns a string with overall information about
\var{hash}, such as the number of entries it contains, the number of
buckets in its hash array, and the utilization of the buckets.
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.19: Regular Expressions
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Regular expressions}
\label{regexp-type}
Regular expressions\mainindex{regular expression} are first class objects in
{\stk}. A regular expression is created by the \ide{string->regexp}
procedure. Matching a regular expression against a string is simply done by
applying a previously created regular expression to this string.
Regular expressions are implemented using code in the Henry Spencer's
package, and much of the description of regular expressions below is copied
from his manual.
\begin{entry}{
\proto{string->regexp}{ string}{procedure}}
\saut
\ide{String->regexp} compiles the \var{string} and returns the
corresponding regular expression.
\smallskip
Matching a regular expression against a string is done by applying the result
of \ide{string->regexp} to this string. This application yields a list of
integer couples if a matching occurs; it returns {\schfalse} otherwise. Those
integers correspond to indexes in the string which match the regular
expression.
A regular expression is zero or more {\em branches}, separated by ``{\tt |}''. It
matches anything that matches one of the branches.
A branch is zero or more {\em pieces}, concatenated. It matches a match for
the first, followed by a match for the second, etc.
A piece is an {\em atom} possibly followed by ``{\tt *}'', ``{\tt +}'', or
``{\tt ?}''. An atom followed by ``{\tt *}'' matches a sequence of 0 or more
matches of the atom. An atom followed by ``{\tt +}'' matches a sequence of 1
or more matches of the atom. An atom followed by ``{\tt ?}'' matches a match
of the atom, or the null string.
An atom is a regular expression in parentheses (matching a match for the
regular expression), a {\em range} (see below), ``{\tt .}'' (matching any
single character), ``{\tt \verb+^+}'' (matching the null string at the
beginning of the input string), ``{\tt \verb|$|}'' % $
(matching the null string
at the end of the input string), a ``{\tt \verb+\+}'' followed by a single
character (matching that character), or a single character with no other
significance (matching that character).
A {\em range} is a sequence of characters enclosed in ``{\tt []}''. It
normally matches any single character from the sequence. If the sequence
begins with ``{\tt \verb+^+}'', it matches any single character {\em not} from
the rest of the sequence. If two characters in the sequence are separated by
``{\tt -}'', this is shorthand for the full list of ASCII characters between
them (e.g. ``{\tt [0-9]}'' matches any decimal digit). To include a literal
``{\tt ]}'' in the sequence, make it the first character (following a possible
``{\tt \verb+^+}''). To include a literal ``{\tt -}'', make it the first or
last character.
In general there may be more than one way to match a regular expression to an
input string. Considering only the rules given so far could lead to
ambiguities. To resolve those ambiguities, the generated regular expression
chooses among alternatives using the rule ``first then longest''. In other
words, it considers the possible matches in order working from left to right
across the input string and the pattern, and it attempts to match longer
pieces of the input string before shorter ones. More specifically, the
following rules apply in decreasing order of priority:
\begin{enumerate}
\item If a regular expression could match two different parts of an
input string then it will match the one that begins earliest.
\item If a regular expression contains ``{\tt |}'' operators then the leftmost
matching sub-expression is chosen.
\item In ``{\tt *}'', ``{\tt +}'', and ``{\tt ?}'' constructs, longer matches are chosen
in preference to shorter ones.
\item In sequences of expression components the components are considered
from left to right.
\end{enumerate}
\begin{scheme}
(define r1 (string->regexp "abc"))
(r1 "xyz") \ev \schfalse
(r1 "12abc345") \ev ((2 5))
(define r2 (string->regexp "[a-z]+"))
(r2 "12abc345") \ev ((2 5))
\end{scheme}
If the regular expression contains parenthesis, and if there is a match, the
result returned by the application will contain several couples of integers.
First couple will be the indexes of the first longest substring which match
the regular expression. Subsequent couples, will be the indexes of all the
sub-parts of this regular expression, in sequence.
\begin{scheme}
(define r3 (string->regexp "(a*)(b*)c"))
(r3 "abc") \ev ((0 3) (0 1) (1 2))
(r3 "c") \ev ((0 1) (0 0) (0 0))
((string->regexp "([a-z]+),([a-z]+)") "XXabcd,eXX")
\ev ((2 8) (2 6) (7 8))
\end{scheme}
\end{entry}
\begin{entry}{
\proto{regexp?}{ obj}{procedure}}
\saut
Returns \schtrue{} if \var{obj} is a regular expression created by
\ide{string->regexp}; otherwise returns {\schfalse}.
\begin{scheme}
(regexp? (string->regexp "[a-zA-Z][a-zA-Z0-9]*"))
\ev \schtrue
\end{scheme}
\end{entry}
\begin{entry}{
\proto{regexp-replace}{ pattern string substitution}{procedure}
\proto{regexp-replace-all}{ pattern string substitution}{procedure}}
\saut
\ide{Regexp-replace} matches the regular expression \var{pattern} against
\var{string}. If there is a match, the portion of \var{string} which match
\var{pattern} is replaced by the \var{substitution} string. If there is no match,
\ide{regexp-replace} returns \var{string} unmodified. Note that the given
\var{pattern} could be here either a string or a regular expression.
\smallskip
If \var{pattern} contains strings of the form ``{\tt \verb+\+n}'',
where {\em n} is a digit between 1 and 9, then it is replaced in the
substitution with the portion of string that matched the {\em n}-th
parenthesized subexpression of {\em pattern}. If {\em n} is equal to
0, then it is replaced in \var{substitution} with the portion of
\var{string} that matched \var{pattern}.
\begin{scheme}
(regexp-replace "a*b" "aaabbcccc" "X")
\ev "Xbcccc"
(regexp-replace (string->regexp "a*b") "aaabbcccc" "X")
\ev "Xbcccc"
(regexp-replace "(a*)b" "aaabbcccc" "X\verb+\\+1Y")
\ev "XaaaYbcccc"
(regexp-replace "(a*)b" "aaabbcccc" "X\verb+\\+0Y")
\ev "XaaabYbcccc"
(regexp-replace "([a-z]*) ([a-z]*)" "john brown" "\verb+\\2 \\1+")
\ev "brown john"
\end{scheme}
\ide{Regexp-replace} replaces the first occurence of \var{pattern} in
\var{string}. To replace {\em all} the occurences of the {\em pattern}, use
\ide{regexp-replace-all}
\begin{scheme}
(regexp-replace "a*b" "aaabbcccc" "X")
\ev "Xbcccc"
(regexp-replace-all "a*b" "aaabbcccc" "X")
\ev "XXcccc"
\end{scheme}
\end{entry}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.20: Pattern matching
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Pattern matching}
Pattern matching\mainindex{Pattern matching} is a key feature of most
modern functional programming languages since it allows clean and
secure code to be written. Internally, ``pattern-matching forms''
should be translated (compiled) into cascades of ``elementary tests''
where code is made as efficient as possible, avoiding redundant tests;
the {\stk} ``pattern matching compiler'' provides this\footnote{The
``pattern matching compiler'' has been written by Jean-Marie Geffroy
and is part of the Manuel Serrano's Bigloo compiler\cite{Serrano-97}
since several years. The code (and documentation) included in {\stk}
has been stolen from the Bigloo package v1.9 (the only difference
between both package is the pattern matching of structures whisch is
absent in {\stk}).}. The technique used is described in details
in~\cite{Queinnec-Geffroy92}, and the code generated can be considered
optimal due to the way this ``pattern compiler'' was obtained.
The ``pattern language'' allows the expression of a wide variety of patterns,
including:
\begin{itemize}
\item Non-linear patterns: pattern variables can appear more than
once, allowing comparison of subparts of the datum (through {\tt eq?})
\item Recursive patterns on lists: for example, checking that the
datum is a list of zero or more {\tt a}s followed by zero or more {\tt
b}s.
\item Pattern matching on lists as well as on vectors.
\end{itemize}
\subsubsection*{Pattern Matching Facilities}
Only two special forms are provided for this: {\tt match-case} and {\tt
match-lambda} and these also exist, for example, in Andrew Wright and
Bruce Duba's~\cite{Wright-Duba-93} pattern matching package.
\begin{entry}{
\proto{match-case}{ \hyper{key} \hyperi{clause} \hyperii{clause}\dotsfoo} {\exprtype}}
\saut
In this form, \hyper{key} may be any expression and each
\hyper{clause} has the form
\begin{scheme}
($<$pat$>$ $<$expression$_{1}$$>$ $<$expression$_{2}$$>$ \ldots)
\end{scheme}
A {\tt match-case} expression is evaluated as
follows. $<$key$>$ is evaluated and the result is compared with each
successive patterns. If the pattern in some $<$clause$>$ yields a match, then
the expressions in that $<$clause$>$ are evaluated from left to right in an
environment where the pattern variables are bound to the corresponding
subparts of the datum, and the result of the last expression in that
$<$clause$>$ is returned as the result of the {\tt match-case} expression.
If no $<$pat$>$ in any $<$clause$>$ matches the datum, then, if there is an
{\tt else} clause, its expressions are evaluated and the result of the last
is the result of the whole {\tt match-case} expression; otherwise the result
of the {\tt match-case} expression is unspecified.
The equality predicate used is {\tt eq?}.
\begin{scheme}
(match-case '(a b a)
((?x ?x) 'foo)
((?x ?- ?x) 'bar)) \lev bar
\end{scheme}
\end{entry}
\begin{entry}{
\proto{match-lambda}{ \hyperi{clause} \hyperii{clause}\dotsfoo} {\exprtype}}
\saut
The form \ide{match-lambda}expands into a lambda-expression expecting
an argument which, once applied to an expression, behaves exactly like
a {\tt match-case} expression.
\begin{scheme}
((match-lambda
((?x ?x) 'foo)
((?x ?- ?x) 'bar)) 'bar) \lev bar
\end{scheme}
\end{entry}
%*---------------------------------------------------------------------*/
\subsubsection*{The pattern language}
The syntax is presented in Table~\ref{PatternLanguage}. It is
described below in the same way (and nearly in the same words) as in
\cite{Wright-Duba-93}.
\begin{table} % [hptb]
%\_\hrulefill\_
\begin{small}
%\begin{minipage}[t]{\textwidth}
\begin{tabular}{ll}
{\em $<$pattern$>$ $\longrightarrow$} & {\em Matches:} \\
$<$atom$>$ $\|$ {\tt (kwote { }}$<$atom$>${\tt )}
& any expression {\tt eq?} to $<$atom$>$\\
$\|$ {\tt (and} $<$pat$_1>$ \ldots $<$pat$_n>${\tt )}
& if all of $<$pat$_i>$ match \\
$\|$ {\tt (or} $<$pat$>$ \ldots $<$pat$_n>${\tt )}
& if any of $<$pat$_1>$ through $<$pat$_n> $match \\
$\|$ {\tt (not} $<$pat$>${\tt )}
& if $<$pat$>$ doesn't match \\
$\|$ {\tt (?} $<$predicate$>${\tt )}
& if $<$predicate$>$ is true\\
$\|$ {\tt ($<$pat$_1>$ \ldots
\footnote{Here, \ldots is a meta-character denoting a finite repetition of patterns. }
$<$pat$_n>$)}
& a list of $n$ elements \\
$\|$ $<$pat$>$ {\tt \underline{\ldots}}
\footnote{Here, {\tt \underline{\ldots}} means the special keyword "\ldots". }
& a (possibly empty) repetition of $<$pat$>$ in a list. \\
$\|$ {\tt \#($<$pat$>$ \ldots $<$pat$_n>$)}
& a vector of n elements \\
$\|$ {\tt ?}$<$identifier$>$ & anything, and binds $identifier$ as a variable \\
$\|$ \verb#?-# & anything \\
$\|$ \verb#??-# & any (possibly empty) repetition of anything in a list \\
$\|$ \verb#???-# & any end of list \\
\end{tabular}
%\end{minipage}
\end{small}
\caption{Pattern Syntax}
\label{PatternLanguage}
\_\hrulefill\_
\end{table}
\begin{note}
{\tt and, or, not, check} and {\tt kwote} must be quoted in order to
be treated as literals. This is the only justification for having
the {\tt kwote} pattern since, by convention, any atom which is not
a keyword is quoted.
\end{note}
\paragraph{Explanations through examples}
\begin{itemize}
\item {\tt ?-} matches any s-expr
\item {\tt a} matches the atom {\tt 'a}.
\item {\tt ?a} matches any expression, and binds the variable {\tt a} to
this expression.
\item {\tt (? integer?)} matches any integer
\item {\tt (a (a b))} matches the only list {\tt '(a (a b))}.
\item {\tt ???-} can only appear at the end of a list, and always succeeds.
For instance, {\tt (a ???-)} is equivalent to {\tt (a . ?-)}.
\item when occurring in a list, {\tt ??-} matches any sequence of anything:
{\tt (a ??- b)} matches any list whose {\tt car} is {\tt a} and last
{\tt car} is {\tt b}.
\item \verb#(a ...)# matches any list of {\tt a}'s, possibly empty.
\item {\tt (?x ?x)} matches any list of length 2 whose {\tt car} is {\em eq} to its {\tt cadr}
\item {\tt ((and (not a) ?x) ?x)} matches any list of length 2 whose {\tt
car} is not {\em eq} to {\tt 'a} but is {\em eq} to its {\tt cadr}
\item {\tt \#(?- ?- ???-)} matches any vector whose length is at least 2.
\end{itemize}
\begin{note}
{\tt ??-} and \verb#...# patterns can not appear
inside a vector, where you should use ???-: For example, {\tt \#(a
??- b)} or {\tt \#(a...)} are invalid patterns, whereas {\tt \#(a
???-)} is valid and matches any vector whose first element is the atom
{\tt a}.
\end{note}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% Section 6.21: Processes
%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Processes}
\label{process-type}
{\stk} provides access to Unix processes as first class objects. Basically,
a process contains four informations: the standard Unix process
identification (aka PID\mainindex{PID}) and the three standard files
of the process.
\begin{entry}{
\proto{run-process}{ command \vri{p} \vrii{p} \vriii{p} \dotsfoo}{procedure}}
\saut
\ide{run-process} creates a new process and run the executable
specified in \var{command}. The \var{p} correspond to the command line
arguments. The following values of \var{p} have a special meaning:
\begin{itemize}
\item {\tt :input} permits to redirect the standard input file of the
process. Redirection can come from a file or from a pipe. To redirect
the standard input from a file, the name of this file must be
specified after {\tt :input}. Use the special keyword {\tt :pipe} to
redirect the standard input from a pipe.
\item {\tt :output} permits to redirect the standard output file of the
process. Redirection can go to a file or to a pipe. To redirect
the standard output to a file, the name of this file must be
specified after {\tt :output}. Use the special keyword {\tt :pipe} to
redirect the standard output to a pipe.
\item {\tt :error} permits to redirect the standard error file of the
process. Redirection can go to a file or to a pipe. To redirect
the standard error to a file, the name of this file must be
specified after {\tt :error}. Use the special keyword {\tt :pipe} to
redirect the standard error to a pipe.
\item {\tt :wait} must be followed by a boolean value. This value
specifies if the process must be run asynchronously or not. By
default, the process is run asynchronously (i.e. {\tt :wait} is
\schfalse).
\item {\tt :host} must be followed by a string. This string represents
the name of the machine on which the command must be executed. This
option uses the external command {\tt rsh}. The shell variable {\tt
PATH} must be correctly set for accessing it without specifying its
abolute path.
\end{itemize}
The following example launches a process which execute the
Unix command {\tt ls} with the arguments {\tt -l} and {\tt
/bin}. The lines printed by this command are stored in the file {\tt /tmp/X}
\begin{scheme}
(run-process "ls" "-l" "/bin" :output "/tmp/X" :wait \schfalse)
\end{scheme}
\end{entry}
\begin{entry}{
\proto{process?}{ process}{procedure}}
\saut
Returns \schtrue{} if \var{process} is a process, otherwise returns
{\schfalse}.
\end{entry}
\begin{entry}{
\proto{process-alive?}{ process}{procedure}}
\saut
Returns \schtrue{} if \var{process} if the process is currently running,
otherwise returns {\schfalse}.
\end{entry}
\begin{entry}{
\proto{process-pid}{ process}{procedure}}
\saut
Returns an integer value which represents the Unix identification
(PID\mainindex{PID}) of \var{process}.
\end{entry}
\begin{entry}{
\proto{process-input}{ process}{procedure}
\proto{process-output}{ process}{procedure}
\proto{process-error}{ process}{procedure}}
\saut
Returns the file port associated to the standard input, output or error
of \var{process}, if it is redirected in (or to) a pipe; otherwise
returns \schfalse. Note that the returned port is opened for reading
when calling {\tt process-output} or {\tt process-error}; it is opened
for writing when calling {\tt process-input}.
\end{entry}
\begin{entry}{
\proto{process-wait}{ process}{procedure}}
\saut
\ide{Process-wait} stops the current process until
\var{process} completion. \ide{Process-wait} returns {\schfalse}
when \var{process} is already terminated; it returns {\schtrue} otherwise.
\end{entry}
\begin{entry}{
\proto{process-exit-status}{ process}{procedure}}
\saut
\ide{Process-exit-status} returns the exit status of \var{process} if
it has finished its execution; returns {\schfalse} otherwise.
\end{entry}
\begin{entry}{
\proto{process-send-signal}{ process n}{procedure}}
\saut
Send the signal whose integer value is \var{n} to \var{process}. Value
of \var{n} is system dependant. Use the defined signal constants to
make your program indpendant of the running system (see
\ref{signals}). The result of \var{process-send-signal} is undefined.
\end{entry}
\begin{entry}{
\proto{process-kill}{ process}{procedure}}
\saut
\ide{Process-kill} brutally kills \var{process}. The result of
\ide{process-kill}
is undefined. This procedure is equivalent to
\begin{scheme}
(process-send-signal process |SIGTERM|)
\end{scheme}
\end{entry}
\begin{entry}{
\proto{process-stop}{ process}{procedure}
\proto{process-continue}{ process}{procedure}}
\saut
Those procedures are only available on systems which support job
control. \var{Process-stop} stops the execution of
\var{process} and \var{process-continue} resumes its execution. They
are equivalent to
\begin{scheme}
(process-send-signal process |SIGSTOP|)
(process-send-signal process |SIGCONT|)
\end{scheme}
\end{entry}
\begin{entry}{
\proto{process-list}{}{procedure}}
\saut
\ide{process-list} returns the list of processes which are currently
running (i.e. alive).
\end{entry}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "manual"
%%% End: