% % STk Reference manual (Part 2) % % Author: Erick Gallesio [eg@unice.fr] % Creation date: ??-Nov-1993 ??:?? % Last file update: 23-Jul-1996 08:59 % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% %%%% 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: 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{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 %%%%%%%%%%%%%% Irgendwann h"alt Gott seine Arme auf: %%%%%%%%%%%%%% BIS HIERHIN UND NICHT WEITER! 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{getcwd}{ string} {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} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% %%%% 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: 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} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% %%%% Section 6.21: Sockets %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Sockets} \label{socket-type} {\stk} defines sockets, on systems which support them, as first class objects. Sockets permits processes to communicate even if they are on different machines. Sockets are useful for creating client-server applications. \begin{entry}{ \proto{make-client-socket}{ hostname port-number}{procedure}} \saut \ide{make-client-socket} returns a new socket object. This socket establishes a link between the running application listening on port \var{port-number} of \var{hostname}. \end{entry} \begin{entry}{ \proto{socket?}{ socket}{procedure}} \saut Returns \schtrue{} if \var{socket} is a socket, otherwise returns {\schfalse}. \end{entry} \begin{entry}{ \proto{socket-host-name}{ socket}{procedure}} \saut Returns a string which contains the name of the distant host attached to \var{socket}. If \var{socket} has been created with \ide{make-client-socket} this procedure returns the official name of the distant machine used for connection. If \var{socket} has been created with \ide{make-server-socket}, this function returns the official name of the client connected to the socket. If no client has used yet the socket, this function returns \schfalse. \end{entry} \begin{entry}{ \proto{socket-host-address}{ socket}{procedure}} \saut Returns a string which contains the IP\mainindex{IP number} number of the distant host attached to \var{socket}. If \var{socket} has been created with \ide{make-client-socket} this procedure returns the IP number of the distant machine used for connection. If \var{socket} has been created with \ide{make-server-socket}, this function returns the address of the client connected to the socket. If no client has used yet the socket, this function returns \schfalse. \end{entry} \begin{entry}{ \proto{socket-local-address}{ socket}{procedure}} \saut Returns a string which contains the IP\mainindex{IP number} number of the local host attached to \var{socket}. \end{entry} \begin{entry}{ \proto{socket-port-number}{ socket}{procedure}} \saut Returns the integer number of the port used for \var{socket}. \end{entry} \begin{entry}{ \proto{socket-input} { socket}{procedure} \proto{socket-output}{ socket}{procedure}} \saut Returns the file port associated for reading or writing with the program connected with \var{socket}. If no connection has already been established, these functions return \schfalse. The following example shows how to make a client socket. Here we create a socket on port 13 of the machine ``{\tt kaolin.unice.fr}''\footnote{Port 13 is generally used for testing: making a connection to it permits to know the distant system's idea of the time of day.}: \begin{scheme} (let ((s (make-client-socket "kaolin.unice.fr" 13))) (format {\schtrue} "Time is: {\tilda}A\verb+\+n" (read-line (socket-input s))) (socket-shutdown s)) \end{scheme} \end{entry} \begin{entry}{ \proto{make-server-socket}{}{procedure} \proto{make-server-socket}{ port-number}{procedure}} \saut \ide{make-server-socket} returns a new socket object. If \var{port-number} is specified, the socket is listening on the specified port; otherwise, the communication port is choosen by the system. \end{entry} \begin{entry}{ \proto{socket-accept-connection}{ socket}{procedure}} \saut \ide{socket-accept-connection} waits for a client connection on the given \var{socket}. If no client is already waiting for a connection, this procedure blocks its caller; otherwise, the first connection request on the queue of pending connections is connected to \var{socket}. This procedure must be called on a server socket created with \ide{make-server-socket}. The result of \ide{socket-accept-connection} is undefined. The following exemple is a simple server which waits for a connection on the port 1234\footnote{Under Unix, you can simply connect to listening socket with the {\tt telnet} command. With the given example, this can be achived by typing the following command in a window shell:\\ {\tt \$ telnet localhost 1234}}. Once the connection with the distant program is established, we read a line on the input port associated to the socket and we write the length of this line on its output port. \begin{scheme} (let ((s (make-server-socket 1234))) (socket-accept-connection s) (let ((l (read-line (socket-input s)))) (format (socket-output s) "Length is: {\tilda}A\verb+\+n" (string-length l)) (flush (socket-output s))) (socket-shutdown s)) \end{scheme} \end{entry} \begin{entry}{ \proto{socket-shutdown}{ socket}{procedure} \proto{socket-shutdown}{ socket close}{procedure}} \saut \ide{Socket-shutdown} shutdowns the connection associated to \var{socket}. \var{Close} is a boolean; it indicates if the socket must be close or not, when the connection is dstroyed. Closing the socket forbids further connections on the same port with the \ide{socket-accept-connection} procedure. Omitting a value for \var{close} implies the closing of socket. The result of \ide{socket-shutdown} is undefined. The following example shows a simple server: when there is a new connection on the port number 1234, the server displays the first line sent to it by the client, discards the others and go back waiting for further client connections. \begin{scheme} (let ((s (make-server-socket 1234))) (let loop () (socket-accept-connection s) (format {\schtrue} "I've read: {\tilda}A\verb+\+n" (read-line (socket-input s))) (socket-shutdown s \schfalse) (loop))) \end{scheme} \end{entry} \begin{entry}{ \proto{socket-down?}{ socket}{procedure}} \saut Returns {\schtrue} if \var{socket} has been previously closed with \ide{socket-shutdown}. It returns {\schfalse} otherwise. \end{entry} \begin{entry}{ \proto{socket-dup}{ socket}{procedure}} \saut Returns a copy of \var{socket}. The original and the copy socket can be used interchangeably. However, if a new connection is accepted on one socket, the characters exchanged on this socket are not visible on the other socket. Duplicating a socket is useful when a server must accept multiple simultaneous connections. The following example creates a server listening on port 1234. This server is duplicated and, once two clients are present, a message is sent on both connections. \begin{scheme} (define s1 (make-server-socket 1234)) (define s2 (socket-dup s1)) (socket-accept-connection s1) (socket-accept-connection s2) ;; blocks until two clients are present (display "Hello,\verb+\+n" (socket-output s1)) (display "world\verb+\+n" (socket-output s2)) (flush (socket-output s1)) (flush (socket-output s2)) \end{scheme} \end{entry} \begin{entry}{ \proto{when-socket-ready}{ socket handler}{procedure} \proto{when-socket-ready}{ socket}{procedure}} \saut Defines a handler for \var{socket}. The handler is a thumk which is executed when a connection is available on \var{socket}. If the special value \schfalse{} is provided as \var{handler}, the current handler for \var{socket} is deleted. If a handler is provided, the value returned by \ide{when-socket-ready} is undefined. Otherwise, it returns the handler currently associated to \var{socket}. This procedure, in conjonction with \ide{socket-dup} permits to build multiple-clients servers which work asynchronously. Such a server is shown below. \begin{scheme} (define p (make-server-socket 1234)) (when-socket-ready p (let ((count 0)) (lambda () (set! count (+ count 1)) (register-connection (socket-dup p) count)))) (define register-connection (let ((sockets '())) (lambda (s cnt) ;; Accept connection (socket-accept-connection s) ;; Save socket somewhere to avoid GC problems (set! sockets (cons s sockets)) ;; Create a handler for reading inputs from this new connection (let ((in (socket-input s)) (out (socket-output s))) (when-port-readable in (lambda () (let ((l (read-line in))) (if (eof-object? l) ;; delete current handler (when-port-readable in \schfalse) ;; Just write the line read on the socket (begin (format out "On {\sharpsign}{\tilda}A --> {\tilda}A\verb+\+n" cnt l) (flush out)))))))))) \end{scheme} \end{entry} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% %%%% Section 6.22: Misc %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Miscellaneous} This section lists the primitives defined in {\stk} that did not fit anywhere else. \begin{entry}{ \proto{eval}{ \hyper{expr}}{syntax} \proto{eval}{ \hyper{expr} \hyper{environment}}{syntax}} \saut Evaluates \hyper{expr} in the given environment. \hyper{Environment} may be omitted, in which case it defaults to the global environment. \begin{scheme} (define foo (let ((a 1)) (lambda () a))) (foo) \ev 1 (eval '(set! a 2) (procedure-environment foo)) (foo) \ev 2 \end{scheme} \end{entry} \begin{entry}{ \proto{version}{} {procedure}} \saut returns a string identifying the current version of {\stk}. \end{entry} \begin{entry}{ \proto{machine-type}{} {procedure}} \saut returns a string identifying the kind of machine which is running the interpreter. The form of the result is {\tt [os-name]-[os-version]-[processor-type]}. \end{entry} \begin{entry}{ \proto{random}{ n} {procedure}} \saut returns an integer in the range 0, $\var{n}-1$ inclusive. \end{entry} \begin{entry}{% \proto{set-random-seed!} { seed} {procedure}} \saut Set the random seed to the specified \var{seed}. {\tt Seed} must be an integer which fits in a C {\tt long int}. \end{entry} \begin{entry}{ \proto{eval-string}{ string environment} {procedure}} \saut Evaluates the contents of the given \var{string} in the given \var{environment} and returns its result. If \var{environment} is omitted it defaults to the global environment. If evaluation leads to an error, the result of \ide{eval-string} is undefined. \begin{scheme} (define x 1) (eval-string "(+ x 1)") \lev 2 (eval-string "x" (let ((x 2)) (the-environment))) \lev 2 \end{scheme} \end{entry} \begin{entry}{ \proto{read-from-string}{ \hyper{string}} {procedure}} \saut Performs a read from the given \var{string}. If \var{string} is the empty string, an end of file object is returned. If an error occurs during string reading, the result of \ide{read-from-string} is undefined. \begin{scheme} (read-from-string "123 456") \lev 123 (read-from-string "") \lev an eof object \end{scheme} \end{entry} \begin{entry}{ \proto{dump}{ string} {procedure}} \saut \ide{Dump} grabs the current continuation \mainindex{continuation} and creates an image of the current {\stk} interpreter in the file whose name is \var{string}{\footnote{ Image creation is not yet implemented on all systems. The current version (\stkversion) allows image dumping only on some platforms: SunOs~4.1.x, Linux~1, FreeBsd}}. This image can be used later to restart the interpreter from the saved state. See the {\stk} man page about the {\tt -image} option for more details. \begin{note} Image creation cannot be done if Tk is initialized. \end{note} \end{entry} \begin{entry}{ \proto{trace-var}{ symbol thunk} {procedure}} \saut \ide{Trace-var} call the given \var{thunk} when the value of the variable denoted by \var{symbol} is changed. \begin{scheme} (define x 1) (define y 0) (trace-var 'x (lambda () (set! y 1))) (set! x 2) (cons x y) \lev (2 . 1) \end{scheme} \begin{note} Several traces can be associated with a single symbol. They are executed in reverse order to their definition. For instance, the execution of \begin{scheme} (begin (trace-var 'z (lambda () (display "One"))) (trace-var 'z (lambda () (display "Two"))) (set! z 10)) \end{scheme} will display the string {\tt"Two"} before the string {\tt"One"} on the current output port. \end{note} \end{entry} \begin{entry}{ \proto{untrace-var}{ symbol} {procedure}} \saut Deletes all the traces associated to the variable denoted by \var{symbol}. \end{entry} \begin{entry}{ \proto{error}{ string \vri{string} \vrii{obj} \dotsfoo}{procedure}} \saut \ide{error} prints the \var{obj}s according to the specification given in \var{string} on the current error port (or in an error window if Tk is initialized\index{Tk toolkit}\index{toolkit}). The specification string follows the ``tilde conventions'' of \ide{format}(see \ref{format}). Once the message is printed, execution returns to toplevel. \end{entry} \begin{entry}{ \proto{gc}{}{procedure}} \saut Runs the garbage collector. See \ref{GCSTART} for the signals associated to garbage collection. \end{entry} \begin{entry}{ \proto{gc-stats}{}{procedure}} \saut % Provides some statistics about current memory usage. This procedure is primarily for debugging the {\stk} interpreter, hence its weird printing format. \end{entry} \begin{entry}{ \proto{expand-heap}{ n}{procedure}} \saut % Expand the heap so that it will contains at least \var{n} cells. Normally, the heap automatically grows when more memory is needed. However, using only automatic heap growing is sometimes very penalizing. This is particulary true for programs which uses a lot of temporary data (which are not pointed by any a variable) and a small amount of global data. In this case, the garbage collector will be often called and the heap will not be automatically expanded (since most of the consumed heap will be reclaimed by the GC). This could be annoying epecially for program where response time is critical. Using \ide{expand-heap} permits to enlarge the heap size (which is set to 20000 cells by default), to avoid those continual calls to the GC. \end{entry} \begin{entry}{ \proto{get-internal-info}{}{procedure}} \saut % Returns a 7-length vector which contains the following informations: \begin{enumerate} \item[0] total cpu used in milli-seconds \item[1] number of cells currently in use. \item[2] total number of allocated cells \item[3] number of cells used since the last call to \ide{get-internal-info} \item[4] number of gc runs \item[5] total time used in the gc \item[6] a boolean indicating if Tk is initialized \end{enumerate} \end{entry} \begin{entry}{ \proto{sort}{ obj predicate}{procedure}} \saut \var{Obj} must be a list or a vector. \ide{Sort} returns a copy of \var{obj} sorted according to \var{predicate}. \var{Predicate} must be a procedure which takes two arguments and returns a true value if the first argument is strictly ``before'' the second. \begin{scheme} (sort '(1 2 -4 12 9 -1 2 3) <) \ev (-4 -1 1 2 2 3 9 12) (sort \sharpsign("one" "two" "three" "four") (lambda (x y) (> (string-length x) (string-length y)))) \ev \sharpsign("three" "four" "one" "two") \end{scheme} \end{entry} \begin{entry}{ \label{uncode} \proto{uncode}{ form}{procedure}} \saut % When {\stk} evaluates an expression it encodes it so that further evaluations of this expression will be more efficient. Since encoded forms are generally difficult to read, \ide{uncode} can be used to (re-)obtain the original form. \begin{scheme} (define (foo a b) (let ((x a) (y (+ b 1))) (cons x y))) (procedure-body foo) \ev (lambda (a b) (let ((x a) (y (+ b 1))) (cons x y))) (foo 1 2) \ev (1 . 3) (procedure-body foo) \ev (lambda (a b) ({\sharpsign}let (x y) ({\sharpsign} ({\sharpsign} {\sharpsign} 1)) ({\sharpsign} {\sharpsign} {\sharpsign}))) (uncode (procedure-body foo)) \ev (lambda (a b) (let ((x a) (y (+ b 1))) (cons x y))) \end{scheme} \begin{note} When a macro has been directly expanded into the macro call code, it is not possible to retrieve the original macro call. Set \ide{*debug*} to {\schtrue} to avoid macro expansion in-lining. \end{note} \end{entry} \begin{entry}{ \proto{time} { \hyper{expr}}{macro}} \saut Evaluates the expression \hyper{expr} in the current environment. Prints the elapsed CPU time and the number of conses used before returning the result of this evaluation. \end{entry} \begin{entry}{% \proto{apropos}{ symbol}{ procedure}} \saut \ide{Apropos} returns a list of symbol whose print name contains the characters of \var{symbol}. Symbols are searched for in the current environment. \begin{scheme} (apropos 'cadd) \lev (caddar caddr cadddr) \end{scheme} \end{entry} \begin{entry}{% \proto{inspect}{ obj}{ procedure}} \saut % \ide{Inspect} permits to graphically inspect an object. The first call of this procedure creates a top level window containing the object to inspect and its current value. If the inspector window is already on screen, \var{obj} will be appended to the list of inspected objects. The inspector window contains menus which permit to call the viewer or detailer on each inspected object. See the on-line documentation for further details. A view of the general inspector is given in figure~1. \begin{note} Tk must be initialized to use \ide{inspect}. \end{note} \begin{figure} \centerline{\psfig{figure={Inspector.ps}}} \caption{A view of the Inspector} \end{figure} \end{entry} \begin{entry}{% \proto{view}{ obj}{ procedure}} \saut % \ide{View} permits to obtain a graphical representation of an {\stk} object. The type of representation depends on the type of the viewed object. Here again, menus are provided to switch to the inspector or to the detailer. See the on-line documentation for more details. A snapshot of the viewer is given in figure~2. \begin{note} Tk must be initialized to use \ide{view}. \end{note} \begin{figure} \centerline{\psfig{figure={View.ps}}} \caption{A view of the Viewer} \end{figure} \end{entry} \begin{entry}{% \proto{detail}{ obj}{ procedure}} \saut % \ide{detail} permits to display the fields of a composite Scheme object. The type of detailer depends on the type of the composite object detailed. Here again, menus are provided to go to the inspector or to the viewer. See the on-line documentation for more details. Figure~3 shows the detailer examining a {\em tk-command}. \begin{note} Tk must be initialized to use \ide{detail}. \end{note} \begin{figure} \centerline{\psfig{figure={Detail.ps}}} \caption{A view of the Detailer} \end{figure} \end{entry} \begin{entry}{% \proto{quit}{ retcode} {procedure} \proto{quit}{} {procedure} \proto{exit}{ retcode} {procedure} \proto{exit}{} {procedure} \proto{bye}{ retcode} {procedure} \proto{bye}{} {procedure}} \saut Exits the {\stk} interpreter with the specified integer return code. If omitted, the interpreter terminates with a return code of 0. \end{entry} %%% Local Variables: %%% mode: latex %%% TeX-master: "manual" %%% End: