This is mit-scheme-ref.info, produced by makeinfo version 4.8 from
scheme.texinfo.

   This manual documents MIT/GNU Scheme 9.1.

   Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993,
1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Massachusetts Institute     of
Technology

     Permission is granted to copy, distribute and/or modify this
     document under the terms of the GNU Free Documentation License,
     Version 1.2 or any later version published by the Free Software
     Foundation; with no Invariant Sections, with no Front-Cover Texts
     and no Back-Cover Texts.  A copy of the license is included in the
     section entitled "GNU Free Documentation License."

INFO-DIR-SECTION Programming Languages
START-INFO-DIR-ENTRY
* MIT/GNU Scheme Ref: (mit-scheme-ref).	MIT/GNU Scheme Reference Manual
END-INFO-DIR-ENTRY


File: mit-scheme-ref.info,  Node: Cutting and Pasting Lists,  Next: Filtering Lists,  Prev: Selecting List Components,  Up: Lists

7.4 Cutting and Pasting Lists
=============================

 -- procedure: sublist list start end
     START and END must be exact integers satisfying

          0 <= START <= END <= (length LIST)

     `sublist' returns a newly allocated list formed from the elements
     of LIST beginning at index START (inclusive) and ending at END
     (exclusive).

 -- procedure: list-head list k
     Returns a newly allocated list consisting of the first K elements
     of LIST.  K must not be greater than the length of LIST.

     We could have defined `list-head' this way:

          (define (list-head list k)
            (sublist list 0 k))

 -- procedure: list-tail list k
     Returns the sublist of LIST obtained by omitting the first K
     elements.  The result, if it is not the empty list, shares
     structure with LIST.  K must not be greater than the length of
     LIST.

 -- procedure: append list ...
     Returns a list consisting of the elements of the first LIST
     followed by the elements of the other LISTs.

          (append '(x) '(y))                      => (x y)
          (append '(a) '(b c d))                  => (a b c d)
          (append '(a (b)) '((c)))                => (a (b) (c))
          (append)                                => ()

     The resulting list is always newly allocated, except that it shares
     structure with the last LIST argument.  The last argument may
     actually be any object; an improper list results if the last
     argument is not a proper list.

          (append '(a b) '(c . d))                => (a b c . d)
          (append '() 'a)                         => a

 -- procedure: append! list ...
     Returns a list that is the argument LISTs concatenated together.
     The arguments are changed rather than copied.  (Compare this with
     `append', which copies arguments rather than destroying them.)  For
     example:

          (define x '(a b c))
          (define y '(d e f))
          (define z '(g h))
          (append! x y z)                         => (a b c d e f g h)
          x                                       => (a b c d e f g h)
          y                                       => (d e f g h)
          z                                       => (g h)

 -- procedure: last-pair list
     Returns the last pair in LIST, which may be an improper list.
     `last-pair' could have been defined this way:

          (define last-pair
            (lambda (x)
              (if (pair? (cdr x))
                  (last-pair (cdr x))
                  x)))

 -- procedure: except-last-pair list
 -- procedure: except-last-pair! list
     These procedures remove the last pair from LIST.  LIST may be an
     improper list, except that it must consist of at least one pair.
     `except-last-pair' returns a newly allocated copy of LIST that
     omits the last pair.  `except-last-pair!' destructively removes
     the last pair from LIST and returns LIST.  If the cdr of LIST is
     not a pair, the empty list is returned by either procedure.


File: mit-scheme-ref.info,  Node: Filtering Lists,  Next: Searching Lists,  Prev: Cutting and Pasting Lists,  Up: Lists

7.5 Filtering Lists
===================

 -- procedure: filter predicate list
     (SRFI 1) Returns a newly allocated copy of LIST containing only
     the elements satisfying PREDICATE.  PREDICATE must be a procedure
     of one argument.

          (filter odd? '(1 2 3 4 5)) => (1 3 5)

     The non-standard procedure `keep-matching-items' (and its alias
     `list-transform-positive') are the same except that its arguments
     are reversed.

 -- procedure: remove predicate list
     (SRFI 1) Like `filter', except that the returned list contains
     only those elements _not_ satisfying PREDICATE.

          (remove odd? '(1 2 3 4 5)) => (2 4)

     The non-standard procedure `delete-matching-items' (and its alias
     `list-transform-negative') are the same except that its arguments
     are reversed.

 -- procedure: partition predicate list
     (SRFI 1) Partitions the elements of LIST with PREDICATE, and
     returns two values: the list of in-elements and the list of
     out-elements.  The LIST is not disordered--elements occur in the
     result lists in the same order as they occur in the argument LIST.
     The dynamic order in which the various applications of `predicate'
     are made is not specified.  One of the returned lists may share a
     common tail with the argument LIST.

          (partition symbol? '(one 2 3 four five 6)) =>
              (one four five)
              (2 3 6)

 -- procedure: filter! predicate list
 -- procedure: remove! predicate list
 -- procedure: partition! predicate list
     (SRFI 1) Linear-update variants of `filter', `remove' and
     `partition'. These procedures are allowed, but not required, to
     alter the cons cells in the argument `list' to construct the
     result lists.

     The non-standard procedures `keep-matching-items!' and
     `delete-matching-items!' bear a similar relationship to
     `keep-matching-items' and `delete-matching-items', respectively.

 -- procedure: delq element list
 -- procedure: delv element list
 -- procedure: delete element list
     Returns a newly allocated copy of LIST with all entries equal to
     ELEMENT removed.  `delq' uses `eq?' to compare ELEMENT with the
     entries in LIST, `delv' uses `eqv?', and `delete' uses `equal?'.

 -- procedure: delq! element list
 -- procedure: delv! element list
 -- procedure: delete! element list
     Returns a list consisting of the top-level elements of LIST with
     all entries equal to ELEMENT removed.  These procedures are like
     `delq', `delv', and `delete' except that they destructively modify
     LIST.  `delq!' uses `eq?' to compare element with the entries in
     LIST, `delv!' uses `eqv?', and `delete!' uses `equal?'.  Because
     the result may not be `eq?' to LIST, it is desirable to do
     something like `(set! x (delete! x))'.

          (define x '(a b c b))
          (delete 'b x)                           => (a c)
          x                                       => (a b c b)

          (define x '(a b c b))
          (delete! 'b x)                          => (a c)
          x                                       => (a c)
          ;; Returns correct result:
          (delete! 'a x)                          => (c)

          ;; Didn't modify what x points to:
          x                                       => (a c)

 -- procedure: delete-member-procedure deletor predicate
     Returns a deletion procedure similar to `delv' or `delete!'.
     DELETOR should be one of the procedures `list-deletor' or
     `list-deletor!'.  PREDICATE must be an equivalence predicate.  The
     returned procedure accepts exactly two arguments: first, an object
     to be deleted, and second, a list of objects from which it is to be
     deleted.  If DELETOR is `list-deletor', the procedure returns a
     newly allocated copy of the given list in which all entries equal
     to the given object have been removed.  If DELETOR is
     `list-deletor!', the procedure returns a list consisting of the
     top-level elements of the given list with all entries equal to the
     given object removed; the given list is destructively modified to
     produce the result.  In either case PREDICATE is used to compare
     the given object to the elements of the given list.

     Here are some examples that demonstrate how
     `delete-member-procedure' could have been used to implement `delv'
     and `delete!':

          (define delv
            (delete-member-procedure list-deletor eqv?))
          (define delete!
            (delete-member-procedure list-deletor! equal?))

 -- procedure: list-deletor predicate
 -- procedure: list-deletor! predicate
     These procedures each return a procedure that deletes elements from
     lists.  PREDICATE must be a procedure of one argument.  The
     returned procedure accepts exactly one argument, which must be a
     proper list, and applies PREDICATE to each of the elements of the
     argument, deleting those for which it is true.

     The procedure returned by `list-deletor' deletes elements
     non-destructively, by returning a newly allocated copy of the
     argument with the appropriate elements removed.  The procedure
     returned by `list-deletor!' performs a destructive deletion.


File: mit-scheme-ref.info,  Node: Searching Lists,  Next: Mapping of Lists,  Prev: Filtering Lists,  Up: Lists

7.6 Searching Lists
===================

 -- procedure: find predicate list
     (SRFI 1) Returns the first element in LIST for which PREDICATE is
     true; returns `#f' if it doesn't find such an element.  PREDICATE
     must be a procedure of one argument.

          (find even? '(3 1 4 1 5 9)) => 4

     Note that `find' has an ambiguity in its lookup semantics--if
     `find' returns `#f', you cannot tell (in general) if it found a
     `#f' element that satisfied PREDICATE, or if it did not find any
     element at all.  In many situations, this ambiguity cannot
     arise--either the list being searched is known not to contain any
     `#f' elements, or the list is guaranteed to have an element
     satisfying PREDICATE.  However, in cases where this ambiguity can
     arise, you should use `find-tail' instead of `find'--`find-tail'
     has no such ambiguity:

          (cond ((find-tail pred lis)
                  => (lambda (pair) ...)) ; Handle (CAR PAIR)
                (else ...)) ; Search failed.

     The non-standard `find-matching-item' procedure (and its alias
     `list-search-positive') works identically except that its argument
     order is reversed.  `list-search-negative' is similar to
     `list-search-positive' but the sense of the predicate is reversed.

 -- procedure: find-tail predicate list
     (SRFI 1) Returns the first pair of LIST whose car satisfies
     PREDICATE; returns `#f' if there's no such pair.  `find-tail' can
     be viewed as a general-predicate variant of MEMV.

 -- procedure: memq object list
 -- procedure: memv object list
 -- procedure: member object list
     These procedures return the first pair of LIST whose car is
     OBJECT; the returned pair is always one from which LIST is
     composed.  If OBJECT does not occur in LIST, `#f' (n.b.: not the
     empty list) is returned.  `memq' uses `eq?' to compare OBJECT with
     the elements of LIST, while `memv' uses `eqv?' and `member' uses
     `equal?'.(1)

          (memq 'a '(a b c))                      => (a b c)
          (memq 'b '(a b c))                      => (b c)
          (memq 'a '(b c d))                      => #f
          (memq (list 'a) '(b (a) c))             => #f
          (member (list 'a) '(b (a) c))           => ((a) c)
          (memq 101 '(100 101 102))               => unspecified
          (memv 101 '(100 101 102))               => (101 102)

 -- procedure: member-procedure predicate
     Returns a procedure similar to `memq', except that PREDICATE,
     which must be an equivalence predicate, is used instead of `eq?'.
     This could be used to define `memv' as follows:

          (define memv (member-procedure eqv?))

   ---------- Footnotes ----------

   (1) Although they are often used as predicates, `memq', `memv', and
`member' do not have question marks in their names because they return
useful values rather than just `#t' or `#f'.


File: mit-scheme-ref.info,  Node: Mapping of Lists,  Next: Reduction of Lists,  Prev: Searching Lists,  Up: Lists

7.7 Mapping of Lists
====================

 -- procedure: map procedure list list ...
     PROCEDURE must be a procedure taking as many arguments as there
     are LISTs.  If more than one LIST is given, then they must all be
     the same length.  `map' applies PROCEDURE element-wise to the
     elements of the LISTs and returns a list of the results, in order
     from left to right.  The dynamic order in which PROCEDURE is
     applied to the elements of the LISTs is unspecified; use
     `for-each' to sequence side effects.

          (map cadr '((a b) (d e) (g h)))           => (b e h)
          (map (lambda (n) (expt n n)) '(1 2 3 4))  => (1 4 27 256)
          (map + '(1 2 3) '(4 5 6))                 => (5 7 9)
          (let ((count 0))
            (map (lambda (ignored)
                   (set! count (+ count 1))
                   count)
                 '(a b c)))                         => unspecified

 -- procedure: map* initial-value procedure list1 list2 ...
     Similar to `map', except that the resulting list is terminated by
     INITIAL-VALUE rather than the empty list.  The following are
     equivalent:

          (map PROCEDURE LIST LIST ...)
          (map* '() PROCEDURE LIST LIST ...)

 -- procedure: append-map procedure list list ...
 -- procedure: append-map* initial-value procedure list list ...
     Similar to `map' and `map*', respectively, except that the results
     of applying PROCEDURE to the elements of LISTs are concatenated
     together by `append' rather than by `cons'.  The following are
     equivalent, except that the former is more efficient:

          (append-map PROCEDURE LIST LIST ...)
          (apply append (map PROCEDURE LIST LIST ...))

 -- procedure: append-map! procedure list list ...
 -- procedure: append-map*! initial-value procedure list list ...
     Similar to `map' and `map*', respectively, except that the results
     of applying PROCEDURE to the elements of LISTs are concatenated
     together by `append!' rather than by `cons'.  The following are
     equivalent, except that the former is more efficient:

          (append-map! PROCEDURE LIST LIST ...)
          (apply append! (map PROCEDURE LIST LIST ...))

 -- procedure: for-each procedure list list ...
     The arguments to `for-each' are like the arguments to `map', but
     `for-each' calls PROCEDURE for its side effects rather than for
     its values.  Unlike `map', `for-each' is guaranteed to call
     PROCEDURE on the elements of the LISTs in order from the first
     element to the last, and the value returned by `for-each' is
     unspecified.

          (let ((v (make-vector 5)))
            (for-each (lambda (i)
                        (vector-set! v i (* i i)))
                      '(0 1 2 3 4))
            v)                            => #(0 1 4 9 16)


File: mit-scheme-ref.info,  Node: Reduction of Lists,  Next: Miscellaneous List Operations,  Prev: Mapping of Lists,  Up: Lists

7.8 Reduction of Lists
======================

 -- procedure: reduce-left procedure initial list
     Combines all the elements of LIST using the binary operation
     PROCEDURE.  For example, using `+' one can add up all the elements:

          (reduce-left + 0 list-of-numbers)

     The argument INITIAL is used only if LIST is empty; in this case
     INITIAL is the result of the call to `reduce-left'.  If LIST has a
     single argument, it is returned.  Otherwise, the arguments are
     reduced in a left-associative fashion.  For example:

          (reduce-left + 0 '(1 2 3 4))            => 10
          (reduce-left + 0 '(1 2))                => 3
          (reduce-left + 0 '(1))                  => 1
          (reduce-left + 0 '())                   => 0
          (reduce-left + 0 '(foo))                => foo
          (reduce-left list '() '(1 2 3 4))       => (((1 2) 3) 4)

 -- procedure: reduce-right procedure initial list
     Like `reduce-left' except that it is right-associative.

          (reduce-right list '() '(1 2 3 4))      => (1 (2 (3 4)))

 -- procedure: fold-right procedure initial list
     Combines all of the elements of LIST using the binary operation
     PROCEDURE.  Unlike `reduce-left' and `reduce-right', INITIAL is
     always used:

          (fold-right + 0 '(1 2 3 4))             => 10
          (fold-right + 0 '(foo))                 error--> Illegal datum
          (fold-right list '() '(1 2 3 4))        => (1 (2 (3 (4 ()))))

     `Fold-right' has interesting properties because it establishes a
     homomorphism between (`cons', `()') and (PROCEDURE, INITIAL).  It
     can be thought of as replacing the pairs in the spine of the list
     with PROCEDURE and replacing the `()' at the end with INITIAL.
     Many of the classical list-processing procedures can be expressed
     in terms of `fold-right', at least for the simple versions that
     take a fixed number of arguments:

          (define (copy-list list)
            (fold-right cons '() list))

          (define (append list1 list2)
            (fold-right cons list2 list1))

          (define (map p list)
            (fold-right (lambda (x r) (cons (p x) r)) '() list))

          (define (reverse items)
            (fold-right (lambda (x r) (append r (list x))) '() items))

 -- procedure: fold-left procedure initial list
     Combines all the elements of LIST using the binary operation
     PROCEDURE.  Elements are combined starting with INITIAL and then
     the elements of LIST from left to right.  Whereas `fold-right' is
     recursive in nature, capturing the essence of `cdr'-ing down a
     list and then computing a result, FOLD-LEFT is iterative in
     nature, combining the elements as the list is traversed.

          (fold-left list '() '(1 2 3 4))         => ((((() 1) 2) 3) 4)

          (define (length list)
            (fold-left (lambda (sum element) (+ sum 1)) 0 list))

          (define (reverse items)
            (fold-left (lambda (x y) (cons y x)) () items))

 -- procedure: any predicate list list ...
     (SRFI 1) Applies PREDICATE across the LISTs, returning true if
     PREDICATE returns true on any application.

     If there are n list arguments LIST1 ...  LISTN, then PREDICATE
     must be a procedure taking n arguments and returning a boolean
     result.

     `any' applies PREDICATE to the first elements of the LIST
     parameters.  If this application returns a true value, `any'
     immediately returns that value.  Otherwise, it iterates, applying
     PREDICATE to the second elements of the LIST parameters, then the
     third, and so forth.  The iteration stops when a true value is
     produced or one of the lists runs out of values; in the latter
     case, `any' returns `#f'.  The application of PREDICATE to the
     last element of the LISTs is a tail call.

     Note the difference between `find' and `any'--`find' returns the
     element that satisfied the predicate; `any' returns the true value
     that the PREDICATE produced.

     Like `every', `any''s name does not end with a question mark--this
     is to indicate that it does not return a simple boolean (`#t' or
     `#f'), but a general value.

          (any integer? '(a 3 b 2.7))   => #t
          (any integer? '(a 3.1 b 2.7)) => #f
          (any < '(3 1 4 1 5)
                 '(2 7 1 8 2)) => #t

     The non-standard procedure `there-exists?' is similar, except that
     it takes a single list and a predicate argument, in that order.

 -- procedure: every predicate list list ...
     (SRFI 1) Applies PREDICATE across the LISTs, returning true if
     PREDICATE returns true on every application.

     If there are n list arguments LIST1 ...  LISTN, then PREDICATE
     must be a procedure taking n arguments and returning a boolean
     result.

     `every' applies PREDICATE to the first elements of the LIST
     parameters.  If this application returns false, `every'
     immediately returns false.  Otherwise, it iterates, applying
     PREDICATE to the second elements of the LIST parameters, then the
     third, and so forth.  The iteration stops when a false value is
     produced or one of the LISTs runs out of values.  In the latter
     case, `every' returns the true value produced by its final
     application of PREDICATE.  The application of PREDICATE to the
     last element of the LISTs is a tail call.

     If one of the clisti has no elements, `every' simply returns `#t'.

     Like `any', `every''s name does not end with a question mark--this
     is to indicate that it does not return a simple boolean (`#t' or
     `#f'), but a general value.

     The non-standard procedure `for-all?' is similar, except that it
     takes a single list and a predicate argument, in that order.


File: mit-scheme-ref.info,  Node: Miscellaneous List Operations,  Prev: Reduction of Lists,  Up: Lists

7.9 Miscellaneous List Operations
=================================

 -- procedure: circular-list object ...
 -- procedure: make-circular-list k [element]
     These procedures are like `list' and `make-list', respectively,
     except that the returned lists are circular.  `circular-list'
     could have been defined like this:

          (define (circular-list . objects)
            (append! objects objects))

     `circular-list' is compatible with SRFI 1, but extended so that it
     can be called with no arguments.

 -- procedure: reverse list
     Returns a newly allocated list consisting of the top-level
     elements of LIST in reverse order.

          (reverse '(a b c))                  => (c b a)
          (reverse '(a (b c) d (e (f))))      => ((e (f)) d (b c) a)

 -- procedure: reverse! list
     Returns a list consisting of the top-level elements of LIST in
     reverse order.  `reverse!' is like `reverse', except that it
     destructively modifies LIST.  Because the result may not be `eqv?'
     to LIST, it is desirable to do something like `(set! x (reverse!
     x))'.

 -- procedure: sort sequence procedure
 -- procedure: merge-sort sequence procedure
 -- procedure: quick-sort sequence procedure
     SEQUENCE must be either a list or a vector.  PROCEDURE must be a
     procedure of two arguments that defines a "total ordering" on the
     elements of SEQUENCE.  In other words, if X and Y are two distinct
     elements of SEQUENCE, then it must be the case that

          (and (PROCEDURE X Y)
               (PROCEDURE Y X))
               => #f

     If SEQUENCE is a list (vector), `sort' returns a newly allocated
     list (vector) whose elements are those of SEQUENCE, except that
     they are rearranged to be sorted in the order defined by
     PROCEDURE.  So, for example, if the elements of SEQUENCE are
     numbers, and PROCEDURE is `<', then the resulting elements are
     sorted in monotonically nondecreasing order.  Likewise, if
     PROCEDURE is `>', the resulting elements are sorted in
     monotonically nonincreasing order.  To be precise, if X and Y are
     any two adjacent elements in the result, where X precedes Y, it is
     the case that

          (PROCEDURE Y X)
               => #f

     Two sorting algorithms are implemented: `merge-sort' and
     `quick-sort'.  The procedure `sort' is an alias for `merge-sort'.

     See also the definition of `sort!'.


File: mit-scheme-ref.info,  Node: Vectors,  Next: Bit Strings,  Prev: Lists,  Up: Top

8 Vectors
*********

"Vectors" are heterogenous structures whose elements are indexed by
exact non-negative integers.  A vector typically occupies less space
than a list of the same length, and the average time required to access
a randomly chosen element is typically less for the vector than for the
list.

   The "length" of a vector is the number of elements that it contains.
This number is an exact non-negative integer that is fixed when the
vector is created.  The "valid indexes" of a vector are the exact
non-negative integers less than the length of the vector.  The first
element in a vector is indexed by zero, and the last element is indexed
by one less than the length of the vector.

   Vectors are written using the notation `#(OBJECT ...)'.  For
example, a vector of length 3 containing the number zero in element 0,
the list `(2 2 2 2)' in element 1, and the string `"Anna"' in element 2
can be written as

     #(0 (2 2 2 2) "Anna")

Note that this is the external representation of a vector, not an
expression evaluating to a vector.  Like list constants, vector
constants must be quoted:

     '#(0 (2 2 2 2) "Anna")          =>  #(0 (2 2 2 2) "Anna")

   A number of the vector procedures operate on subvectors.  A
"subvector" is a segment of a vector that is specified by two exact
non-negative integers, START and END.  START is the index of the first
element that is included in the subvector, and END is one greater than
the index of the last element that is included in the subvector.  Thus
if START and END are the same, they refer to a null subvector, and if
START is zero and END is the length of the vector, they refer to the
entire vector.  The "valid indexes" of a subvector are the exact
integers between START inclusive and END exclusive.

* Menu:

* Construction of Vectors::
* Selecting Vector Components::
* Cutting Vectors::
* Modifying Vectors::


File: mit-scheme-ref.info,  Node: Construction of Vectors,  Next: Selecting Vector Components,  Prev: Vectors,  Up: Vectors

8.1 Construction of Vectors
===========================

 -- procedure: make-vector k [object]
     Returns a newly allocated vector of K elements.  If OBJECT is
     specified, `make-vector' initializes each element of the vector to
     OBJECT.  Otherwise the initial elements of the result are
     unspecified.

 -- procedure: vector object ...
     Returns a newly allocated vector whose elements are the given
     arguments.  `vector' is analogous to `list'.

          (vector 'a 'b 'c)                       =>  #(a b c)

 -- procedure: vector-copy vector
     Returns a newly allocated vector that is a copy of VECTOR.

 -- procedure: list->vector list
     Returns a newly allocated vector initialized to the elements of
     LIST.  The inverse of `list->vector' is `vector->list'.

          (list->vector '(dididit dah))           =>  #(dididit dah)

 -- procedure: make-initialized-vector k initialization
     Similar to `make-vector', except that the elements of the result
     are determined by calling the procedure INITIALIZATION on the
     indices.  For example:

          (make-initialized-vector 5 (lambda (x) (* x x)))
               =>  #(0 1 4 9 16)

 -- procedure: vector-grow vector k
     K must be greater than or equal to the length of VECTOR.  Returns
     a newly allocated vector of length K.  The first `(vector-length
     VECTOR)' elements of the result are initialized from the
     corresponding elements of VECTOR.  The remaining elements of the
     result are unspecified.

 -- procedure: vector-map procedure vector
     PROCEDURE must be a procedure of one argument.  `vector-map'
     applies PROCEDURE element-wise to the elements of VECTOR and
     returns a newly allocated vector of the results, in order from
     left to right.  The dynamic order in which PROCEDURE is applied to
     the elements of VECTOR is unspecified.

          (vector-map cadr '#((a b) (d e) (g h)))     =>  #(b e h)
          (vector-map (lambda (n) (expt n n)) '#(1 2 3 4))
                                                      =>  #(1 4 27 256)
          (vector-map + '#(5 7 9))                    =>  #(5 7 9)


File: mit-scheme-ref.info,  Node: Selecting Vector Components,  Next: Cutting Vectors,  Prev: Construction of Vectors,  Up: Vectors

8.2 Selecting Vector Components
===============================

 -- procedure: vector? object
     Returns `#t' if OBJECT is a vector; otherwise returns `#f'.

 -- procedure: vector-length vector
     Returns the number of elements in VECTOR.

 -- procedure: vector-ref vector k
     Returns the contents of element K of VECTOR.  K must be a valid
     index of VECTOR.

          (vector-ref '#(1 1 2 3 5 8 13 21) 5)    =>  8

 -- procedure: vector-set! vector k object
     Stores OBJECT in element K of VECTOR and returns an unspecified
     value.  K must be a valid index of VECTOR.

          (let ((vec (vector 0 '(2 2 2 2) "Anna")))
            (vector-set! vec 1 '("Sue" "Sue"))
            vec)
               =>  #(0 ("Sue" "Sue") "Anna")

 -- procedure: vector-first vector
 -- procedure: vector-second vector
 -- procedure: vector-third vector
 -- procedure: vector-fourth vector
 -- procedure: vector-fifth vector
 -- procedure: vector-sixth vector
 -- procedure: vector-seventh vector
 -- procedure: vector-eighth vector
     These procedures access the first several elements of VECTOR in
     the obvious way.  It is an error if the implicit index of one of
     these procedurs is not a valid index of VECTOR.

 -- procedure: vector-binary-search vector key<? unwrap-key key
     Searches VECTOR for an element with a key matching KEY, returning
     the element if one is found or `#f' if none.  The search operation
     takes time proportional to the logarithm of the length of VECTOR.
     UNWRAP-KEY must be a procedure that maps each element of VECTOR to
     a key.  KEY<? must be a procedure that implements a total ordering
     on the keys of the elements.

          (define (translate number)
            (vector-binary-search '#((1 . i)
                                     (2 . ii)
                                     (3 . iii)
                                     (6 . vi))
                                  < car number))
          (translate 2)  =>  (2 . ii)
          (translate 4)  =>  #F


File: mit-scheme-ref.info,  Node: Cutting Vectors,  Next: Modifying Vectors,  Prev: Selecting Vector Components,  Up: Vectors

8.3 Cutting Vectors
===================

 -- procedure: subvector vector start end
     Returns a newly allocated vector that contains the elements of
     VECTOR between index START (inclusive) and END (exclusive).

 -- procedure: vector-head vector end
     Equivalent to

          (subvector VECTOR 0 END)

 -- procedure: vector-tail vector start
     Equivalent to

          (subvector VECTOR START (vector-length VECTOR))


File: mit-scheme-ref.info,  Node: Modifying Vectors,  Prev: Cutting Vectors,  Up: Vectors

8.4 Modifying Vectors
=====================

 -- procedure: vector-fill! vector object
 -- procedure: subvector-fill! vector start end object
     Stores OBJECT in every element of the vector (subvector) and
     returns an unspecified value.

 -- procedure: subvector-move-left! vector1 start1 end1 vector2 start2
 -- procedure: subvector-move-right! vector1 start1 end1 vector2 start2
     Destructively copies the elements of VECTOR1, starting with index
     START1 (inclusive) and ending with END1 (exclusive), into VECTOR2
     starting at index START2 (inclusive).  VECTOR1, START1, and END1
     must specify a valid subvector, and START2 must be a valid index
     for VECTOR2.  The length of the source subvector must not exceed
     the length of VECTOR2 minus the index START2.

     The elements are copied as follows (note that this is only
     important when VECTOR1 and VECTOR2 are `eqv?'):

    `subvector-move-left!'
          The copy starts at the left end and moves toward the right
          (from smaller indices to larger).  Thus if VECTOR1 and
          VECTOR2 are the same, this procedure moves the elements
          toward the left inside the vector.

    `subvector-move-right!'
          The copy starts at the right end and moves toward the left
          (from larger indices to smaller).  Thus if VECTOR1 and
          VECTOR2 are the same, this procedure moves the elements
          toward the right inside the vector.

 -- procedure: sort! vector procedure
 -- procedure: merge-sort! vector procedure
 -- procedure: quick-sort! vector procedure
     PROCEDURE must be a procedure of two arguments that defines a
     "total ordering" on the elements of VECTOR.  The elements of
     VECTOR are rearranged so that they are sorted in the order defined
     by PROCEDURE.  The elements are rearranged in place, that is,
     VECTOR is destructively modified so that its elements are in the
     new order.

     `sort!' returns VECTOR as its value.

     Two sorting algorithms are implemented: `merge-sort!' and
     `quick-sort!'.  The procedure `sort!' is an alias for
     `merge-sort!'.

     See also the definition of `sort'.


File: mit-scheme-ref.info,  Node: Bit Strings,  Next: Miscellaneous Datatypes,  Prev: Vectors,  Up: Top

9 Bit Strings
*************

A "bit string" is a sequence of bits.  Bit strings can be used to
represent sets or to manipulate binary data.  The elements of a bit
string are numbered from zero up to the number of bits in the string
less one, in _right to left order_, (the rightmost bit is numbered
zero).  When you convert from a bit string to an integer, the zero-th
bit is associated with the zero-th power of two, the first bit is
associated with the first power, and so on.

   Bit strings are encoded very densely in memory.  Each bit occupies
exactly one bit of storage, and the overhead for the entire bit string
is bounded by a small constant.  However, accessing a bit in a bit
string is slow compared to accessing an element of a vector or character
string.  If performance is of overriding concern, it is better to use
character strings to store sets of boolean values even though they
occupy more space.

   The "length" of a bit string is the number of bits that it contains.
This number is an exact non-negative integer that is fixed when the bit
string is created.  The "valid indexes" of a bit string are the exact
non-negative integers less than the length of the bit string.

   Bit strings may contain zero or more bits.  They are not limited by
the length of a machine word.  In the printed representation of a bit
string, the contents of the bit string are preceded by `#*'.  The
contents are printed starting with the most significant bit (highest
index).

   Note that the external representation of bit strings uses a bit
ordering that is the reverse of the representation for bit strings in
Common Lisp.  It is likely that MIT/GNU Scheme's representation will be
changed in the future, to be compatible with Common Lisp.  For the time
being this representation should be considered a convenience for viewing
bit strings rather than a means of entering them as data.

     #*11111
     #*1010
     #*00000000
     #*

   All of the bit-string procedures are MIT/GNU Scheme extensions.

* Menu:

* Construction of Bit Strings::
* Selecting Bit String Components::
* Cutting and Pasting Bit Strings::
* Bitwise Operations on Bit Strings::
* Modification of Bit Strings::
* Integer Conversions of Bit Strings::


File: mit-scheme-ref.info,  Node: Construction of Bit Strings,  Next: Selecting Bit String Components,  Prev: Bit Strings,  Up: Bit Strings

9.1 Construction of Bit Strings
===============================

 -- procedure: make-bit-string k initialization
     Returns a newly allocated bit string of length K.  If
     INITIALIZATION is `#f', the bit string is filled with 0 bits;
     otherwise, the bit string is filled with 1 bits.

          (make-bit-string 7 #f)                  =>  #*0000000

 -- procedure: bit-string-allocate k
     Returns a newly allocated bit string of length K, but does not
     initialize it.

 -- procedure: bit-string-copy bit-string
     Returns a newly allocated copy of BIT-STRING.


File: mit-scheme-ref.info,  Node: Selecting Bit String Components,  Next: Cutting and Pasting Bit Strings,  Prev: Construction of Bit Strings,  Up: Bit Strings

9.2 Selecting Bit String Components
===================================

 -- procedure: bit-string? object
     Returns `#t' if OBJECT is a bit string; otherwise returns `#f'.

 -- procedure: bit-string-length bit-string
     Returns the length of BIT-STRING.

 -- procedure: bit-string-ref bit-string k
     Returns `#t' if the Kth bit is 1; otherwise returns `#f'.  K must
     be a valid index of BIT-STRING.

 -- procedure: bit-string-set! bit-string k
     Sets the Kth bit in BIT-STRING to 1 and returns an unspecified
     value.  K must be a valid index of BIT-STRING.

 -- procedure: bit-string-clear! bit-string k
     Sets the Kth bit in BIT-STRING to 0 and returns an unspecified
     value.  K must be a valid index of BIT-STRING.

 -- procedure: bit-substring-find-next-set-bit bit-string start end
     Returns the index of the first occurrence of a set bit in the
     substring of BIT-STRING from START (inclusive) to END (exclusive).
     If none of the bits in the substring are set `#f' is returned.
     The index returned is relative to the whole bit string, not
     substring.

     The following procedure uses `bit-substring-find-next-set-bit' to
     find all the set bits and display their indexes:

          (define (scan-bitstring bs)
            (let ((end (bit-string-length bs)))
              (let loop ((start 0))
                (let ((next
                       (bit-substring-find-next-set-bit bs start end)))
                  (if next
                      (begin
                        (write-line next)
                        (if (< next end)
                            (loop (+ next 1)))))))))


File: mit-scheme-ref.info,  Node: Cutting and Pasting Bit Strings,  Next: Bitwise Operations on Bit Strings,  Prev: Selecting Bit String Components,  Up: Bit Strings

9.3 Cutting and Pasting Bit Strings
===================================

 -- procedure: bit-string-append bit-string-1 bit-string-2
     Appends the two bit string arguments, returning a newly allocated
     bit string as its result.  In the result, the bits copied from
     BIT-STRING-1 are less significant (smaller indices) than those
     copied from BIT-STRING-2.

 -- procedure: bit-substring bit-string start end
     Returns a newly allocated bit string whose bits are copied from
     BIT-STRING, starting at index START (inclusive) and ending at END
     (exclusive).


File: mit-scheme-ref.info,  Node: Bitwise Operations on Bit Strings,  Next: Modification of Bit Strings,  Prev: Cutting and Pasting Bit Strings,  Up: Bit Strings

9.4 Bitwise Operations on Bit Strings
=====================================

 -- procedure: bit-string-zero? bit-string
     Returns `#t' if BIT-STRING contains only 0 bits; otherwise returns
     `#f'.

 -- procedure: bit-string=? bit-string-1 bit-string-2
     Compares the two bit string arguments and returns `#t' if they are
     the same length and contain the same bits; otherwise returns `#f'.

 -- procedure: bit-string-not bit-string
     Returns a newly allocated bit string that is the bitwise-logical
     negation of BIT-STRING.

 -- procedure: bit-string-movec! target-bit-string bit-string
     The destructive version of `bit-string-not'.  The arguments
     TARGET-BIT-STRING and BIT-STRING must be bit strings of the same
     length.  The bitwise-logical negation of BIT-STRING is computed
     and the result placed in TARGET-BIT-STRING.  The value of this
     procedure is unspecified.

 -- procedure: bit-string-and bit-string-1 bit-string-2
     Returns a newly allocated bit string that is the bitwise-logical
     "and" of the arguments.  The arguments must be bit strings of
     identical length.

 -- procedure: bit-string-andc bit-string-1 bit-string-2
     Returns a newly allocated bit string that is the bitwise-logical
     "and" of BIT-STRING-1 with the bitwise-logical negation of
     BIT-STRING-2.  The arguments must be bit strings of identical
     length.

 -- procedure: bit-string-or bit-string-1 bit-string-2
     Returns a newly allocated bit string that is the bitwise-logical
     "inclusive or" of the arguments.  The arguments must be bit
     strings of identical length.

 -- procedure: bit-string-xor bit-string-1 bit-string-2
     Returns a newly allocated bit string that is the bitwise-logical
     "exclusive or" of the arguments.  The arguments must be bit
     strings of identical length.

 -- procedure: bit-string-and! target-bit-string bit-string
 -- procedure: bit-string-or! target-bit-string bit-string
 -- procedure: bit-string-xor! target-bit-string bit-string
 -- procedure: bit-string-andc! target-bit-string bit-string
     These are destructive versions of the above operations.  The
     arguments TARGET-BIT-STRING and BIT-STRING must be bit strings of
     the same length.  Each of these procedures performs the
     corresponding bitwise-logical operation on its arguments, places
     the result into TARGET-BIT-STRING, and returns an unspecified
     result.


File: mit-scheme-ref.info,  Node: Modification of Bit Strings,  Next: Integer Conversions of Bit Strings,  Prev: Bitwise Operations on Bit Strings,  Up: Bit Strings

9.5 Modification of Bit Strings
===============================

 -- procedure: bit-string-fill! bit-string initialization
     Fills BIT-STRING with zeroes if INITIALIZATION is `#f'; otherwise
     fills BIT-STRING with ones.  Returns an unspecified value.

 -- procedure: bit-string-move! target-bit-string bit-string
     Moves the contents of BIT-STRING into TARGET-BIT-STRING.  Both
     arguments must be bit strings of the same length.  The results of
     the operation are undefined if the arguments are the same bit
     string.

 -- procedure: bit-substring-move-right! bit-string-1 start1 end1
          bit-string-2 start2
     Destructively copies the bits of BIT-STRING-1, starting at index
     START1 (inclusive) and ending at END1 (exclusive), into
     BIT-STRING-2 starting at index START2 (inclusive).  START1 and
     END1 must be valid substring indices for BIT-STRING-1, and START2
     must be a valid index for BIT-STRING-2.  The length of the source
     substring must not exceed the length of BIT-STRING-2 minus the
     index START2.

     The bits are copied starting from the MSB and working towards the
     LSB; the direction of copying only matters when BIT-STRING-1 and
     BIT-STRING-2 are `eqv?'.


File: mit-scheme-ref.info,  Node: Integer Conversions of Bit Strings,  Prev: Modification of Bit Strings,  Up: Bit Strings

9.6 Integer Conversions of Bit Strings
======================================

 -- procedure: unsigned-integer->bit-string length integer
     Both LENGTH and INTEGER must be exact non-negative integers.
     Converts INTEGER into a newly allocated bit string of LENGTH bits.
     Signals an error of type `condition-type:bad-range-argument' if
     INTEGER is too large to be represented in LENGTH bits.  

 -- procedure: signed-integer->bit-string length integer
     LENGTH must be an exact non-negative integer, and INTEGER may be
     any exact integer.  Converts INTEGER into a newly allocated bit
     string of LENGTH bits, using two's complement encoding for
     negative numbers.  Signals an error of type
     `condition-type:bad-range-argument' if INTEGER is too large to be
     represented in LENGTH bits.  

 -- procedure: bit-string->unsigned-integer bit-string
 -- procedure: bit-string->signed-integer bit-string
     Converts BIT-STRING into an exact integer.
     `bit-string->signed-integer' regards BIT-STRING as a two's
     complement representation of a signed integer, and produces an
     integer of like sign and absolute value.
     `bit-string->unsigned-integer' regards BIT-STRING as an unsigned
     quantity and converts to an integer accordingly.


File: mit-scheme-ref.info,  Node: Miscellaneous Datatypes,  Next: Associations,  Prev: Bit Strings,  Up: Top

10 Miscellaneous Datatypes
**************************

* Menu:

* Booleans::
* Symbols::
* Cells::
* Records::
* Promises::
* Streams::
* Weak Pairs::
* Ephemerons::


File: mit-scheme-ref.info,  Node: Booleans,  Next: Symbols,  Prev: Miscellaneous Datatypes,  Up: Miscellaneous Datatypes

10.1 Booleans
=============

The "boolean objects" are "true" and "false".  The boolean constant
true is written as `#t', and the boolean constant false is written as
`#f'.

   The primary use for boolean objects is in the conditional expressions
`if', `cond', `and', and `or'; the behavior of these expressions is
determined by whether objects are true or false.  These expressions
count only `#f' as false.  They count everything else, including `#t',
pairs, symbols, numbers, strings, vectors, and procedures as true (but
*note True and False::).

   Programmers accustomed to other dialects of Lisp should note that
Scheme distinguishes `#f' and the empty list from the symbol `nil'.
Similarly, `#t' is distinguished from the symbol `t'.  In fact, the
boolean objects (and the empty list) are not symbols at all.

   Boolean constants evaluate to themselves, so you don't need to quote
them.

     #t                                      =>  #t
     #f                                      =>  #f
     '#f                                     =>  #f
     t                                       error--> Unbound variable

 -- variable: false
 -- variable: true
     These variables are bound to the objects `#f' and `#t'
     respectively.  The compiler, given the `usual-integrations'
     declaration, replaces references to these variables with their
     respective values.

     Note that the symbol `true' is not equivalent to `#t', and the
     symbol `false' is not equivalent to `#f'.

 -- procedure: boolean? object
     Returns `#t' if OBJECT is either `#t' or `#f'; otherwise returns
     `#f'.

          (boolean? #f)                           =>  #t
          (boolean? 0)                            =>  #f

 -- procedure: not object
 -- procedure: false? object
     These procedures return `#t' if OBJECT is false; otherwise they
     return `#f'.  In other words they _invert_ boolean values.  These
     two procedures have identical semantics; their names are different
     to give different connotations to the test.

          (not #t)                                =>  #f
          (not 3)                                 =>  #f
          (not (list 3))                          =>  #f
          (not #f)                                =>  #t

 -- procedure: boolean=? obj1 obj2
     This predicate is true iff OBJ1 and OBJ2 are either both true or
     both false.

 -- procedure: boolean/and object ...
     This procedure returns `#t' if none of its arguments are `#f'.
     Otherwise it returns `#f'.

 -- procedure: boolean/or object ...
     This procedure returns `#f' if all of its arguments are `#f'.
     Otherwise it returns `#t'.


File: mit-scheme-ref.info,  Node: Symbols,  Next: Cells,  Prev: Booleans,  Up: Miscellaneous Datatypes

10.2 Symbols
============

MIT/GNU Scheme provides two types of symbols: "interned" and
"uninterned".  Interned symbols are far more common than uninterned
symbols, and there are more ways to create them.  Interned symbols have
an external representation that is recognized by the procedure `read';
uninterned symbols do not.(1)

   Interned symbols have an extremely useful property: any two interned
symbols whose names are the same, in the sense of `string=?', are the
same object (i.e. they are `eq?' to one another).  The term "interned"
refers to the process of "interning" by which this is accomplished.
Uninterned symbols do not share this property.

   The names of interned symbols are not distinguished by their
alphabetic case.  Because of this, MIT/GNU Scheme converts all
alphabetic characters in the name of an interned symbol to a specific
case (lower case) when the symbol is created.  When the name of an
interned symbol is referenced (using `symbol->string') or written (using
`write') it appears in this case.  It is a bad idea to depend on the
name being lower case.  In fact, it is preferable to take this one step
further: don't depend on the name of a symbol being in a uniform case.

   The rules for writing an interned symbol are the same as the rules
for writing an identifier (*note Identifiers::).  Any interned symbol
that has been returned as part of a literal expression, or read using
the `read' procedure and subsequently written out using the `write'
procedure, will read back in as the identical symbol (in the sense of
`eq?').

   Usually it is also true that reading in an interned symbol that was
previously written out produces the same symbol.  An exception are
symbols created by the procedures `string->symbol' and `intern'; they
can create symbols for which this write/read invariance may not hold
because the symbols' names contain special characters or letters in the
non-standard case.(2)

   The external representation for uninterned symbols is special, to
distinguish them from interned symbols and prevent them from being
recognized by the `read' procedure:

     (string->uninterned-symbol "foo")
          =>  #[uninterned-symbol 30 foo]

   In this section, the procedures that return symbols as values will
either always return interned symbols, or always return uninterned
symbols.  The procedures that accept symbols as arguments will always
accept either interned or uninterned symbols, and do not distinguish the
two.

 -- procedure: symbol? object
     Returns `#t' if OBJECT is a symbol, otherwise returns `#f'.

          (symbol? 'foo)                                  =>  #t
          (symbol? (car '(a b)))                          =>  #t
          (symbol? "bar")                                 =>  #f

 -- procedure: symbol->string symbol
     Returns the name of SYMBOL as a string.  If SYMBOL was returned by
     `string->symbol', the value of this procedure will be identical
     (in the sense of `string=?') to the string that was passed to
     `string->symbol'.  It is an error to apply mutation procedures
     such as `string-set!' to strings returned by this procedure.

          (symbol->string 'flying-fish)           =>  "flying-fish"
          (symbol->string 'Martin)                =>  "martin"
          (symbol->string (string->symbol "Malvina"))
                                                  =>  "Malvina"

     Note that two distinct uninterned symbols can have the same name.

 -- procedure: intern string
     Returns the interned symbol whose name is STRING.  Converts STRING
     to the standard alphabetic case before generating the symbol.
     This is the preferred way to create interned symbols, as it
     guarantees the following independent of which case the
     implementation uses for symbols' names:

          (eq? 'bitBlt (intern "bitBlt")) =>     #t

     The user should take care that STRING obeys the rules for
     identifiers (*note Identifiers::), otherwise the resulting symbol
     cannot be read as itself.

 -- procedure: intern-soft string
     Returns the interned symbol whose name is STRING.  Converts STRING
     to the standard alphabetic case before generating the symbol.  If
     no such interned symbol exists, returns `#f'.

     This is exactly like `intern', except that it will not create an
     interned symbol, but only returns symbols that already exist.

 -- procedure: string->symbol string
     Returns the interned symbol whose name is STRING.  Although you
     can use this procedure to create symbols with names containing
     special characters or lowercase letters, it's usually a bad idea
     to create such symbols because they cannot be read as themselves.
     See `symbol->string'.

          (eq? 'mISSISSIppi 'mississippi)         =>  #t
          (string->symbol "mISSISSIppi")
               =>  the symbol with the name "mISSISSIppi"
          (eq? 'bitBlt (string->symbol "bitBlt")) =>  #f
          (eq? 'JollyWog
                (string->symbol
                  (symbol->string 'JollyWog)))    =>  #t
          (string=? "K. Harper, M.D."
                     (symbol->string
                       (string->symbol
                         "K. Harper, M.D.")))     =>  #t

 -- procedure: string->uninterned-symbol string
     Returns a newly allocated uninterned symbol whose name is STRING.
     It is unimportant what case or characters are used in STRING.

     Note: this is the fastest way to make a symbol.

 -- procedure: generate-uninterned-symbol [object]
     Returns a newly allocated uninterned symbol that is guaranteed to
     be different from any other object.  The symbol's name consists of
     a prefix string followed by the (exact non-negative integer) value
     of an internal counter.  The counter is initially zero, and is
     incremented after each call to this procedure.

     The optional argument OBJECT is used to control how the symbol is
     generated.  It may take one of the following values:

        * If OBJECT is omitted or `#f', the prefix is `"G"'.

        * If OBJECT is an exact non-negative integer, the internal
          counter is set to that integer prior to generating the result.

        * If OBJECT is a string, it is used as the prefix.

        * If OBJECT is a symbol, its name is used as the prefix.

          (generate-uninterned-symbol)
               =>  #[uninterned-symbol 31 G0]
          (generate-uninterned-symbol)
               =>  #[uninterned-symbol 32 G1]
          (generate-uninterned-symbol 'this)
               =>  #[uninterned-symbol 33 this2]
          (generate-uninterned-symbol)
               =>  #[uninterned-symbol 34 G3]
          (generate-uninterned-symbol 100)
               =>  #[uninterned-symbol 35 G100]
          (generate-uninterned-symbol)
               =>  #[uninterned-symbol 36 G101]

 -- procedure: symbol-append symbol ...
     Returns the interned symbol whose name is formed by concatenating
     the names of the given symbols.  This procedure preserves the case
     of the names of its arguments, so if one or more of the arguments'
     names has non-standard case, the result will also have
     non-standard case.

          (symbol-append 'foo- 'bar)              =>  foo-bar
          ;; the arguments may be uninterned:
          (symbol-append 'foo- (string->uninterned-symbol "baz"))
                                                  =>  foo-baz
          ;; the result has the same case as the arguments:
          (symbol-append 'foo- (string->symbol "BAZ"))    =>  foo-BAZ

 -- procedure: symbol-hash symbol
     Returns a hash number for SYMBOL, which is computed by calling
     `string-hash' on SYMBOL's name.  The hash number is an exact
     non-negative integer.

 -- procedure: symbol-hash-mod symbol modulus
     MODULUS must be an exact positive integer.  Equivalent to

          (modulo (symbol-hash SYMBOL) MODULUS)

     This procedure is provided for convenience in constructing hash
     tables.  However, it is normally preferable to use
     `make-strong-eq-hash-table' to build hash tables keyed by symbols,
     because `eq?' hash tables are much faster.

 -- procedure: symbol<? symbol1 symbol2
     This procedure computes a total order on symbols.  It is
     equivalent to

          (string<? (symbol->string SYMBOL1)
                    (symbol->string SYMBOL2))

   ---------- Footnotes ----------

   (1) In older dialects of Lisp, uninterned symbols were fairly
important.  This was true because symbols were complicated data
structures: in addition to having value cells (and sometimes, function
cells), these structures contained "property lists".  Because of this,
uninterned symbols were often used merely for their property lists --
sometimes an uninterned symbol used this way was referred to as a
"disembodied property list".  In MIT/GNU Scheme, symbols do not have
property lists, or any other components besides their names.  There is
a different data structure similar to disembodied property lists:
one-dimensional tables (*note 1D Tables::).  For these reasons,
uninterned symbols are not very useful in MIT/GNU Scheme.  In fact,
their primary purpose is to simplify the generation of unique variable
names in programs that generate Scheme code.

   (2) MIT/GNU Scheme reserves a specific set of interned symbols for
its own use.  If you use these reserved symbols it is possible that you
could break specific pieces of software that depend on them.  The
reserved symbols all have names beginning with the characters `#[' and
ending with the character `]'; thus none of these symbols can be read
by the procedure `read' and hence are not likely to be used by accident.
For example, `(intern "#[unnamed-procedure]")' produces a reserved
symbol.


File: mit-scheme-ref.info,  Node: Cells,  Next: Records,  Prev: Symbols,  Up: Miscellaneous Datatypes

10.3 Cells
==========

"Cells" are data structures similar to pairs except that they have only
one element.  They are useful for managing state.

 -- procedure: cell? object
     Returns `#t' if OBJECT is a cell; otherwise returns `#f'.

 -- procedure: make-cell object
     Returns a newly allocated cell whose contents is OBJECT.

 -- procedure: cell-contents cell
     Returns the current contents of CELL.

 -- procedure: set-cell-contents! cell object
     Alters the contents of CELL to be OBJECT.  Returns an unspecified
     value.

 -- procedure: bind-cell-contents! cell object thunk
     Alters the contents of CELL to be OBJECT, calls THUNK with no
     arguments, then restores the original contents of CELL and returns
     the value returned by THUNK.  This is completely equivalent to
     dynamic binding of a variable, including the behavior when
     continuations are used (*note Dynamic Binding::).


File: mit-scheme-ref.info,  Node: Records,  Next: Promises,  Prev: Cells,  Up: Miscellaneous Datatypes

10.4 Records
============

MIT/GNU Scheme provides a "record" abstraction, which is a simple and
flexible mechanism for building structures with named components.
Records can be defined and accessed using the procedures defined in this
section.  A less flexible but more concise way to manipulate records is
to use the `define-structure' special form (*note Structure
Definitions::).  

 -- procedure: make-record-type type-name field-names
     Returns a "record-type descriptor", a value representing a new data
     type, disjoint from all others.  The TYPE-NAME argument must be a
     string, but is only used for debugging purposes (such as the
     printed representation of a record of the new type).  The
     FIELD-NAMES argument is a list of symbols naming the "fields" of a
     record of the new type.  It is an error if the list contains any
     duplicates.  It is unspecified how record-type descriptors are
     represented.

 -- procedure: record-constructor record-type [field-names]
     Returns a procedure for constructing new members of the type
     represented by RECORD-TYPE.  The returned procedure accepts
     exactly as many arguments as there are symbols in the given list,
     FIELD-NAMES; these are used, in order, as the initial values of
     those fields in a new record, which is returned by the constructor
     procedure.  The values of any fields not named in the list of
     FIELD-NAMES are unspecified.  The FIELD-NAMES argument defaults to
     the list of field-names in the call to `make-record-type' that
     created the type represented by RECORD-TYPE; if the FIELD-NAMES
     argument is provided, it is an error if it contains any duplicates
     or any symbols not in the default list.

 -- procedure: record-keyword-constructor record-type
     Returns a procedure for constructing new members of the type
     represented by RECORD-TYPE.  The returned procedure accepts
     arguments in a "keyword list", which is an alternating sequence of
     names and values.  In other words, the number of arguments must be
     a multiple of two, and every other argument, starting with the
     first argument, must be a symbol that is one of the field names
     for RECORD-TYPE.

     The returned procedure may be called with a keyword list that
     contains multiple instances of the same keyword.  In this case,
     the leftmost instance is used and the other instances are ignored.
     This allows keyword lists to be accumulated using `cons' or
     `cons*', and new bindings added to the front of the list override
     old bindings at the end.

 -- procedure: record-predicate record-type
     Returns a procedure for testing membership in the type represented
     by RECORD-TYPE.  The returned procedure accepts exactly one
     argument and returns `#t' if the argument is a member of the
     indicated record type; it returns `#f' otherwise.

 -- procedure: record-accessor record-type field-name
     Returns a procedure for reading the value of a particular field of
     a member of the type represented by RECORD-TYPE.  The returned
     procedure accepts exactly one argument which must be a record of
     the appropriate type; it returns the current value of the field
     named by the symbol FIELD-NAME in that record.  The symbol
     FIELD-NAME must be a member of the list of field names in the call
     to `make-record-type' that created the type represented by
     RECORD-TYPE.

 -- procedure: record-modifier record-type field-name
     Returns a procedure for writing the value of a particular field of
     a member of the type represented by RECORD-TYPE.  The returned
     procedure accepts exactly two arguments: first, a record of the
     appropriate type, and second, an arbitrary Scheme value; it
     modifies the field named by the symbol FIELD-NAME in that record
     to contain the given value.  The returned value of the modifier
     procedure is unspecified.  The symbol FIELD-NAME must be a member
     of the list of field names in the call to `make-record-type' that
     created the type represented by RECORD-TYPE.

 -- procedure: record? object
     Returns `#t' if OBJECT is a record of any type and `#f' otherwise.
     Note that `record?' may be true of any Scheme value; of course,
     if it returns `#t' for some particular value, then
     `record-type-descriptor' is applicable to that value and returns an
     appropriate descriptor.

 -- procedure: record-type-descriptor record
     Returns the record-type descriptor representing the type of
     RECORD.  That is, for example, if the returned descriptor were
     passed to `record-predicate', the resulting predicate would return
     `#t' when passed RECORD.  Note that it is not necessarily the case
     that the returned descriptor is the one that was passed to
     `record-constructor' in the call that created the constructor
     procedure that created RECORD.

 -- procedure: record-type? object
     Returns `#t' if OBJECT is a record-type descriptor; otherwise
     returns `#f'.

 -- procedure: record-type-name record-type
     Returns the type name associated with the type represented by
     RECORD-TYPE.  The returned value is `eqv?' to the TYPE-NAME
     argument given in the call to `make-record-type' that created the
     type represented by RECORD-TYPE.

 -- procedure: record-type-field-names record-type
     Returns a list of the symbols naming the fields in members of the
     type represented by RECORD-TYPE.  The returned value is `equal?'
     to the FIELD-NAMES argument given in the call to
     `make-record-type' that created the type represented by
     RECORD-TYPE.(1)

   ---------- Footnotes ----------

   (1) In MIT/GNU Scheme, the returned list is always newly allocated.


File: mit-scheme-ref.info,  Node: Promises,  Next: Streams,  Prev: Records,  Up: Miscellaneous Datatypes

10.5 Promises
=============

 -- special form: delay expression
     The `delay' construct is used together with the procedure `force'
     to implement "lazy evaluation" or "call by need".  `(delay
     EXPRESSION)' returns an object called a "promise" which at some
     point in the future may be asked (by the `force' procedure) to
     evaluate EXPRESSION and deliver the resulting value.

 -- procedure: force promise
     Forces the value of _promise_.  If no value has been computed for
     the promise, then a value is computed and returned.  The value of
     the promise is cached (or "memoized") so that if it is forced a
     second time, the previously computed value is returned without any
     recomputation.

          (force (delay (+ 1 2)))                 =>  3

          (let ((p (delay (+ 1 2))))
            (list (force p) (force p)))           =>  (3 3)

          (define head car)

          (define tail
            (lambda (stream)
              (force (cdr stream))))

          (define a-stream
            (letrec ((next
                      (lambda (n)
                        (cons n (delay (next (+ n 1)))))))
              (next 0)))

          (head (tail (tail a-stream)))           =>  2

 -- procedure: promise? object
     Returns `#t' if OBJECT is a promise; otherwise returns `#f'.

 -- procedure: promise-forced? promise
     Returns `#t' if PROMISE has been forced and its value cached;
     otherwise returns `#f'.

 -- procedure: promise-value promise
     If PROMISE has been forced and its value cached, this procedure
     returns the cached value.  Otherwise, an error is signalled.

   `force' and `delay' are mainly intended for programs written in
functional style.  The following examples should not be considered to
illustrate good programming style, but they illustrate the property that
the value of a promise is computed at most once.

     (define count 0)

     (define p
       (delay
        (begin
          (set! count (+ count 1))
          (* x 3))))

     (define x 5)

     count                                   =>  0
     p                                       =>  #[promise 54]
     (force p)                               =>  15
     p                                       =>  #[promise 54]
     count                                   =>  1
     (force p)                               =>  15
     count                                   =>  1

   Here is a possible implementation of `delay' and `force'.  We define
the expression

     (delay EXPRESSION)

to have the same meaning as the procedure call

     (make-promise (lambda () EXPRESSION))

where `make-promise' is defined as follows:

     (define make-promise
       (lambda (proc)
         (let ((already-run? #f)
               (result #f))
           (lambda ()
             (cond ((not already-run?)
                    (set! result (proc))
                    (set! already-run? #t)))
             result))))

   Promises are implemented here as procedures of no arguments, and
`force' simply calls its argument.

     (define force
       (lambda (promise)
         (promise)))

   Various extensions to this semantics of `delay' and `force' are
supported in some implementations (none of these are currently
supported in MIT/GNU Scheme):

   * Calling `force' on an object that is not a promise may simply
     return the object.

   * It may be the case that there is no means by which a promise can be
     operationally distinguished from its forced value.  That is,
     expressions like the following may evaluate to either `#t' or `#f',
     depending on the implementation:

          (eqv? (delay 1) 1)              =>  unspecified
          (pair? (delay (cons 1 2)))      =>  unspecified

   * Some implementations will implement "implicit forcing", where the
     value of a promise is forced by primitive procedures like `car' and
     `+':

          (+ (delay (* 3 7)) 13)          =>  34


File: mit-scheme-ref.info,  Node: Streams,  Next: Weak Pairs,  Prev: Promises,  Up: Miscellaneous Datatypes

10.6 Streams
============

In addition to promises, MIT/GNU Scheme supports a higher-level
abstraction called "streams".  Streams are similar to lists, except
that the tail of a stream is not computed until it is referred to.
This allows streams to be used to represent infinitely long lists.

 -- procedure: stream object ...
     Returns a newly allocated stream whose elements are the arguments.
     Note that the expression `(stream)' returns the empty stream, or
     end-of-stream marker.

 -- procedure: list->stream list
     Returns a newly allocated stream whose elements are the elements of
     LIST.  Equivalent to `(apply stream LIST)'.

 -- procedure: stream->list stream
     Returns a newly allocated list whose elements are the elements of
     STREAM.  If STREAM has infinite length this procedure will not
     terminate.  This could have been defined by

          (define (stream->list stream)
            (if (stream-null? stream)
                '()
                (cons (stream-car stream)
                      (stream->list (stream-cdr stream)))))

 -- special form: cons-stream object expression
     Returns a newly allocated stream pair.  Equivalent to `(cons
     OBJECT (delay EXPRESSION))'.

 -- procedure: stream-pair? object
     Returns `#t' if OBJECT is a pair whose cdr contains a promise.
     Otherwise returns `#f'.  This could have been defined by

          (define (stream-pair? object)
            (and (pair? object)
                 (promise? (cdr object))))

 -- procedure: stream-car stream
 -- procedure: stream-first stream
     Returns the first element in STREAM.  `stream-car' is equivalent
     to `car'.  `stream-first' is a synonym for `stream-car'.

 -- procedure: stream-cdr stream
 -- procedure: stream-rest stream
     Returns the first tail of STREAM.  Equivalent to `(force (cdr
     STREAM))'.  `stream-rest' is a synonym for `stream-cdr'.

 -- procedure: stream-null? stream
     Returns `#t' if STREAM is the end-of-stream marker; otherwise
     returns `#f'.  This is equivalent to `null?', but should be used
     whenever testing for the end of a stream.

 -- procedure: stream-length stream
     Returns the number of elements in STREAM.  If STREAM has an
     infinite number of elements this procedure will not terminate.
     Note that this procedure forces all of the promises that comprise
     STREAM.

 -- procedure: stream-ref stream k
     Returns the element of STREAM that is indexed by K; that is, the
     Kth element.  K must be an exact non-negative integer strictly
     less than the length of STREAM.

 -- procedure: stream-head stream k
     Returns the first K elements of STREAM as a list.  K must be an
     exact non-negative integer strictly less than the length of STREAM.

 -- procedure: stream-tail stream k
     Returns the tail of STREAM that is indexed by K; that is, the Kth
     tail.  This is equivalent to performing `stream-cdr' K times.  K
     must be an exact non-negative integer strictly less than the
     length of STREAM.

 -- procedure: stream-map procedure stream stream ...
     Returns a newly allocated stream, each element being the result of
     invoking PROCEDURE with the corresponding elements of the STREAMs
     as its arguments.


File: mit-scheme-ref.info,  Node: Weak Pairs,  Next: Ephemerons,  Prev: Streams,  Up: Miscellaneous Datatypes

10.7 Weak Pairs
===============

"Weak pairs" are a mechanism for building data structures that point at
objects without protecting them from garbage collection.  The car of a
weak pair holds its pointer weakly, while the cdr holds its pointer in
the normal way.  If the object in the car of a weak pair is not held
normally by any other data structure, it will be garbage-collected.

   Note: weak pairs are _not_ pairs; that is, they do not satisfy the
predicate `pair?'.

 -- procedure: weak-pair? object
     Returns `#t' if OBJECT is a weak pair; otherwise returns `#f'.

 -- procedure: weak-cons car cdr
     Allocates and returns a new weak pair, with components CAR and
     CDR.  The CAR component is held weakly.

 -- procedure: weak-pair/car? weak-pair
     This predicate returns `#f' if the car of WEAK-PAIR has been
     garbage-collected; otherwise returns `#t'.  In other words, it is
     true if WEAK-PAIR has a valid car component.

 -- procedure: weak-car weak-pair
     Returns the car component of WEAK-PAIR.  If the car component has
     been garbage-collected, this operation returns `#f', but it can
     also return `#f' if that is the value that was stored in the car.

   Normally, `weak-pair/car?' is used to determine if `weak-car' would
return a valid value.  An obvious way of doing this would be:

     (if (weak-pair/car? x)
         (weak-car x)
         ...)

However, since a garbage collection could occur between the call to
`weak-pair/car?' and `weak-car', this would not always work correctly.
Instead, the following should be used, which always works:

     (or (weak-car x)
         (and (not (weak-pair/car? x))
              ...))

   The reason that the latter expression works is that `weak-car'
returns `#f' in just two instances: when the car component is `#f', and
when the car component has been garbage-collected.  In the former case,
if a garbage collection happens between the two calls, it won't matter,
because `#f' will never be garbage-collected.  And in the latter case,
it also won't matter, because the car component no longer exists and
cannot be affected by the garbage collector.

 -- procedure: weak-set-car! weak-pair object
     Sets the car component of WEAK-PAIR to OBJECT and returns an
     unspecified result.

 -- procedure: weak-cdr weak-pair
     Returns the cdr component of WEAK-CDR.

 -- procedure: weak-set-cdr! weak-pair object
     Sets the cdr component of WEAK-PAIR to OBJECT and returns an
     unspecified result.


File: mit-scheme-ref.info,  Node: Ephemerons,  Prev: Weak Pairs,  Up: Miscellaneous Datatypes

10.8 Ephemerons
===============

An "ephemeron" is an object with two weakly referenced components
called its "key" and "datum".  The garbage collector drops an
ephemeron's references to both key and datum, rendering the ephemeron
"broken", if and only if the garbage collector can prove that there are
no strong references to the key.  In other words, an ephemeron is
broken when nobody else cares about its key.  Note that an ephemeron's
reference to its datum may be dropped even if the datum is still
reachable; all that matters is whether the key is reachable.  Once
broken, ephemerons never cease to be broken; setting the key or datum
of a broken ephemeron with `set-ephemeron-key!' or
`set-ephemeron-datum!' has no effect.

   Ephemerons are considerably heavier-weight than weak pairs, because
garbage-collecting ephemerons is more complicated than
garbage-collecting weak pairs.  Each ephemeron needs five words of
storage, rather than the two words needed by a weak pair.  However,
while the garbage collector spends more time on ephemerons than on
other objects, the amount of time it spends on ephemerons scales
linearly with the number of live ephemerons, which is how its running
time scales with the total number of live objects anyway.

 -- procedure: ephemeron? object
     Returns `#t' if OBJECT is a ephemeron; otherwise returns `#f'.

 -- procedure: make-ephemeron key datum
     Allocates and returns a new ephemeron, with components KEY and
     DATUM.

 -- procedure: ephemeron-broken? ephemeron
     Returns `#t' if the garbage collector has dropped EPHEMERON's
     references to its key and datum; otherwise returns `#f'.

 -- procedure: ephemeron-key ephemeron
 -- procedure: ephemeron-datum ephemeron
     These return the key or datum component, respectively, of
     EPHEMERON.  If EPHEMERON has been broken, these operations return
     `#f', but they can also return `#f' if that is the value that was
     stored in the key or value component.

 -- procedure: set-ephemeron-key! ephemeron object
 -- procedure: set-ephemeron-datum! ephemeron object
     These set the key or datum component, respectively, of EPHEMERON
     to OBJECT and return an unspecified result.  If EPHEMERON is
     broken, neither of these operations has any effect.

   Like `weak-pair/car?', `ephemeron-broken?' must be used with care.
`Ephemeron-broken?' on an ephemeron guarantees that any prior call to
`ephemeron-key' or `ephemeron-datum' on the same ephemeron yielded the
key or datum that was stored in the ephemeron, but it makes no
guarantees about subsequent calls to `ephemeron-key' or
`ephemeron-datum'.  Thus, the correct idiom to fetch an ephemeron's key
and datum and use them if the ephemeron is not broken is

     (let ((key (ephemeron-key ephemeron))
           (datum (ephemeron-datum ephemeron)))
       (if (ephemeron-broken? ephemeron)
           ... broken case ...
           ... code using KEY and DATUM ...))


File: mit-scheme-ref.info,  Node: Associations,  Next: Procedures,  Prev: Miscellaneous Datatypes,  Up: Top

11 Associations
***************

MIT/GNU Scheme provides several mechanisms for associating objects with
one another.  Each of these mechanisms creates a link between one or
more objects, called "keys", and some other object, called a "datum".
Beyond this common idea, however, each of the mechanisms has various
different properties that make it appropriate in different situations:

   * "Association lists" are one of Lisp's oldest association
     mechanisms.  Because they are made from ordinary pairs, they are
     easy to build and manipulate, and very flexible in use.  However,
     the average lookup time for an association list is linear in the
     number of associations.

   * "1D tables" have a very simple interface, making them easy to use,
     and offer the feature that they do not prevent their keys from
     being reclaimed by the garbage collector.  Like association lists,
     their average lookup time is linear in the number of associations;
     but 1D tables aren't as flexible.

   * "The association table" is MIT/GNU Scheme's equivalent to the
     "property lists" of Lisp.  It has the advantages that the keys may
     be any type of object and that it does not prevent the keys from
     being reclaimed by the garbage collector.  However, two
     linear-time lookups must be performed, one for each key, whereas
     for traditional property lists only one lookup is required for
     both keys.

   * "Hash tables" are a powerful mechanism with constant-time access to
     large amounts of data.  Hash tables are not as flexible as
     association lists, but because their access times are independent
     of the number of associations in the table, for most applications
     they are the mechanism of choice.

   * "Balanced binary trees" are another association mechanism that is
     useful for applications in which the keys are ordered.  Binary
     trees have access times that are proportional to the logarithm of
     the number of associations in the tree.  While they aren't as fast
     as hash tables, they offer the advantage that the contents of the
     tree can be converted to a sorted alist in linear time.
     Additionally, two trees can be compared for equality in worst-case
     linear time.

   * "Red-Black trees" are a kind of balanced binary tree.  The
     implementation supports destructive insertion and deletion
     operations with a good constant factor.

   * "Weight-Balanced trees" are a kind of balanced binary tree.  The
     implementation provides non-destructive operations.  There is a
     comprehensive set of operations, including: a constant-time size
     operation; many high-level operations such as the set operations
     union, intersection and difference; and indexing of elements by
     position.


* Menu:

* Association Lists::
* 1D Tables::
* The Association Table::
* Hash Tables::
* Object Hashing::
* Red-Black Trees::
* Weight-Balanced Trees::


File: mit-scheme-ref.info,  Node: Association Lists,  Next: 1D Tables,  Prev: Associations,  Up: Associations

11.1 Association Lists
======================

An "association list", or "alist", is a data structure used very
frequently in Scheme.  An alist is a list of pairs, each of which is
called an "association".  The car of an association is called the "key".

   An advantage of the alist representation is that an alist can be
incrementally augmented simply by adding new entries to the front.
Moreover, because the searching procedures `assv' et al. search the
alist in order, new entries can "shadow" old entries.  If an alist is
viewed as a mapping from keys to data, then the mapping can be not only
augmented but also altered in a non-destructive manner by adding new
entries to the front of the alist.(1)

 -- procedure: alist? object
     Returns `#t' if OBJECT is an association list (including the empty
     list); otherwise returns `#f'.  Any OBJECT satisfying this
     predicate also satisfies `list?'.

 -- procedure: assq object alist
 -- procedure: assv object alist
 -- procedure: assoc object alist
     These procedures find the first pair in ALIST whose car field is
     OBJECT, and return that pair; the returned pair is always an
     _element_ of ALIST, _not_ one of the pairs from which ALIST is
     composed.  If no pair in ALIST has OBJECT as its car, `#f' (n.b.:
     not the empty list) is returned.  `assq' uses `eq?' to compare
     OBJECT with the car fields of the pairs in ALIST, while `assv'
     uses `eqv?' and `assoc' uses `equal?'.(2)

          (define e '((a 1) (b 2) (c 3)))
          (assq 'a e)                             =>  (a 1)
          (assq 'b e)                             =>  (b 2)
          (assq 'd e)                             =>  #f
          (assq (list 'a) '(((a)) ((b)) ((c))))   =>  #f
          (assoc (list 'a) '(((a)) ((b)) ((c))))  =>  ((a))
          (assq 5 '((2 3) (5 7) (11 13)))         =>  unspecified
          (assv 5 '((2 3) (5 7) (11 13)))         =>  (5 7)

 -- procedure: association-procedure predicate selector
     Returns an association procedure that is similar to `assv', except
     that SELECTOR (a procedure of one argument) is used to select the
     key from the association, and PREDICATE (an equivalence predicate)
     is used to compare the key to the given item.  This can be used to
     make association lists whose elements are, say, vectors instead of
     pairs (also *note Searching Lists::).

     For example, here is how `assv' could be implemented:

          (define assv (association-procedure eqv? car))

     Another example is a "reverse association" procedure:

          (define rassv (association-procedure eqv? cdr))

 -- procedure: del-assq object alist
 -- procedure: del-assv object alist
 -- procedure: del-assoc object alist
     These procedures return a newly allocated copy of ALIST in which
     all associations with keys equal to OBJECT have been removed.
     Note that while the returned copy is a newly allocated list, the
     association pairs that are the elements of the list are shared with
     ALIST, not copied.  `del-assq' uses `eq?' to compare OBJECT with
     the keys, while `del-assv' uses `eqv?' and `del-assoc' uses
     `equal?'.

          (define a
            '((butcher . "231 e22nd St.")
              (baker . "515 w23rd St.")
              (hardware . "988 Lexington Ave.")))

          (del-assq 'baker a)
               =>
               ((butcher . "231 e22nd St.")
                (hardware . "988 Lexington Ave."))

 -- procedure: del-assq! object alist
 -- procedure: del-assv! object alist
 -- procedure: del-assoc! object alist
     These procedures remove from ALIST all associations with keys
     equal to OBJECT.  They return the resulting list.  `del-assq!'
     uses `eq?' to compare OBJECT with the keys, while `del-assv!' uses
     `eqv?' and `del-assoc!' uses `equal?'.  These procedures are like
     `del-assq', `del-assv', and `del-assoc', respectively, except that
     they destructively modify ALIST.

 -- procedure: delete-association-procedure deletor predicate selector
     This returns a deletion procedure similar to `del-assv' or
     `del-assq!'.  The PREDICATE and SELECTOR arguments are the same as
     those for `association-procedure', while the DELETOR argument
     should be either the procedure `list-deletor' (for non-destructive
     deletions), or the procedure `list-deletor!' (for destructive
     deletions).

     For example, here is a possible implementation of `del-assv':

          (define del-assv
            (delete-association-procedure list-deletor eqv? car))

 -- procedure: alist-copy alist
     Returns a newly allocated copy of ALIST.  This is similar to
     `list-copy' except that the "association" pairs, i.e. the elements
     of the list ALIST, are also copied.  `alist-copy' could have been
     implemented like this:

          (define (alist-copy alist)
            (if (null? alist)
                '()
                (cons (cons (car (car alist)) (cdr (car alist)))
                      (alist-copy (cdr alist)))))

   ---------- Footnotes ----------

   (1) This introduction is taken from `Common Lisp, The Language',
second edition, p. 431.

   (2) Although they are often used as predicates, `assq', `assv', and
`assoc' do not have question marks in their names because they return
useful values rather than just `#t' or `#f'.


File: mit-scheme-ref.info,  Node: 1D Tables,  Next: The Association Table,  Prev: Association Lists,  Up: Associations

11.2 1D Tables
==============

"1D tables" ("one-dimensional" tables) are similar to association
lists.  In a 1D table, unlike an association list, the keys of the table
are held "weakly": if a key is garbage-collected, its associated value
in the table is removed.  1D tables compare their keys for equality
using `eq?'.

   1D tables can often be used as a higher-performance alternative to
the two-dimensional association table (*note The Association Table::).
If one of the keys being associated is a compound object such as a
vector, a 1D table can be stored in one of the vector's slots.  Under
these circumstances, accessing items in a 1D table will be comparable in
performance to using a property list in a conventional Lisp.

 -- procedure: make-1d-table
     Returns a newly allocated empty 1D table.

 -- procedure: 1d-table? object
     Returns `#t' if OBJECT is a 1D table, otherwise returns `#f'.  Any
     object that satisfies this predicate also satisfies `list?'.

 -- procedure: 1d-table/put! 1d-table key datum
     Creates an association between KEY and DATUM in 1D-TABLE.  Returns
     an unspecified value.

 -- procedure: 1d-table/remove! 1d-table key
     Removes any association for KEY in 1D-TABLE and returns an
     unspecified value.

 -- procedure: 1d-table/get 1d-table key default
     Returns the DATUM associated with KEY in 1D-TABLE.  If there is no
     association for KEY, DEFAULT is returned.

 -- procedure: 1d-table/lookup 1d-table key if-found if-not-found
     IF-FOUND must be a procedure of one argument, and IF-NOT-FOUND
     must be a procedure of no arguments.  If 1D-TABLE contains an
     association for KEY, IF-FOUND is invoked on the DATUM of the
     association.  Otherwise, IF-NOT-FOUND is invoked with no
     arguments.  In either case, the result of the invoked procedure is
     returned as the result of `1d-table/lookup'.

 -- procedure: 1d-table/alist 1d-table
     Returns a newly allocated association list that contains the same
     information as 1D-TABLE.


File: mit-scheme-ref.info,  Node: The Association Table,  Next: Hash Tables,  Prev: 1D Tables,  Up: Associations

11.3 The Association Table
==========================

MIT/GNU Scheme provides a generalization of the property-list mechanism
found in most other implementations of Lisp: a global two-dimensional
"association table".  This table is indexed by two keys, called X-KEY
and Y-KEY in the following procedure descriptions.  These keys and the
datum associated with them can be arbitrary objects.  `eq?' is used to
discriminate keys.

   Think of the association table as a matrix: a single datum can be
accessed using both keys, a column using X-KEY only, and a row using
Y-KEY only.

 -- procedure: 2d-put! x-key y-key datum
     Makes an entry in the association table that associates DATUM with
     X-KEY and Y-KEY.  Returns an unspecified result.

 -- procedure: 2d-remove! x-key y-key
     If the association table has an entry for X-KEY and Y-KEY, it is
     removed.  Returns an unspecified result.

 -- procedure: 2d-get x-key y-key
     Returns the DATUM associated with X-KEY and Y-KEY.  Returns `#f'
     if no such association exists.

 -- procedure: 2d-get-alist-x x-key
     Returns an association list of all entries in the association
     table that are associated with X-KEY.  The result is a list of
     `(Y-KEY . DATUM)' pairs.  Returns the empty list if no entries for
     X-KEY exist.

          (2d-put! 'foo 'bar 5)
          (2d-put! 'foo 'baz 6)
          (2d-get-alist-x 'foo)           =>  ((baz . 6) (bar . 5))

 -- procedure: 2d-get-alist-y y-key
     Returns an association list of all entries in the association
     table that are associated with Y-KEY.  The result is a list of
     `(X-KEY . DATUM)' pairs.  Returns the empty list if no entries for
     Y-KEY exist.

          (2d-put! 'bar 'foo 5)
          (2d-put! 'baz 'foo 6)
          (2d-get-alist-y 'foo)           =>  ((baz . 6) (bar . 5))


File: mit-scheme-ref.info,  Node: Hash Tables,  Next: Object Hashing,  Prev: The Association Table,  Up: Associations

11.4 Hash Tables
================

Hash tables are a fast, powerful mechanism for storing large numbers of
associations.  MIT/GNU Scheme's hash tables feature automatic resizing,
customizable growth parameters, and customizable hash procedures.

   The average times for the insertion, deletion, and lookup operations
on a hash table are bounded by a constant.  The space required by the
table is proportional to the number of associations in the table; the
constant of proportionality is described below (*note Resizing of Hash
Tables::).

   (Previously, the hash-table implementation was a run-time-loadable
option, but as of release 7.7.0 it is loaded by default.  It's no longer
necessary to call `load-option' prior to using hash tables.)

* Menu:

* Construction of Hash Tables::
* Basic Hash Table Operations::
* Resizing of Hash Tables::
* Address Hashing::


File: mit-scheme-ref.info,  Node: Construction of Hash Tables,  Next: Basic Hash Table Operations,  Prev: Hash Tables,  Up: Hash Tables

11.4.1 Construction of Hash Tables
----------------------------------

The next few procedures are hash-table constructors.  All hash table
constructors are procedures that accept one optional argument,
INITIAL-SIZE, and return a newly allocated hash table.  If INITIAL-SIZE
is given, it must be an exact non-negative integer or `#f'.  The
meaning of INITIAL-SIZE is discussed below (*note Resizing of Hash
Tables::).

   Hash tables are normally characterized by two things: the equivalence
predicate that is used to compare keys, and whether or not the table
allows its keys to be reclaimed by the garbage collector.  If a table
prevents its keys from being reclaimed by the garbage collector, it is
said to hold its keys "strongly"; otherwise it holds its keys "weakly"
(*note Weak Pairs::).

 -- procedure: make-strong-eq-hash-table [initial-size]
     Returns a newly allocated hash table that accepts arbitrary
     objects as keys, and compares those keys with `eq?'.  The keys are
     held strongly.  These are the fastest of the standard hash tables.

 -- procedure: make-weak-eq-hash-table [initial-size]
     Returns a newly allocated hash table that accepts arbitrary
     objects as keys, and compares those keys with `eq?'.  The keys are
     held weakly.

 -- procedure: make-eq-hash-table [initial-size]
     This is an alias for `make-weak-eq-hash-table'.

     *Warning*:  This become an alias `make-strong-eq-hash-table'
     instead.  We recommend that you use `make-weak-eq-hash-table'
     explicitly for weak hash tables.

 -- procedure: make-strong-eqv-hash-table [initial-size]
     Returns a newly allocated hash table that accepts arbitrary
     objects as keys, and compares those keys with `eqv?'.  The keys
     are held strongly.  These hash tables are a little slower than
     those made by `make-strong-eq-hash-table'.

 -- procedure: make-weak-eqv-hash-table [initial-size]
     Returns a newly allocated hash table that accepts arbitrary
     objects as keys, and compares those keys with `eqv?'.  The keys
     are held weakly, except that booleans, characters, numbers, and
     interned symbols are held strongly.

 -- procedure: make-eqv-hash-table [initial-size]
     This is an alias for `make-weak-eqv-hash-table'.

     *Warning*:  This become an alias for `make-strong-eqv-hash-table'
     instead.  We recommend that you use `make-weak-eqv-hash-table'
     explicitly for weak hash tables.

 -- procedure: make-equal-hash-table [initial-size]
     Returns a newly allocated hash table that accepts arbitrary
     objects as keys, and compares those keys with `equal?'.  The keys
     are held strongly.  These hash tables are quite a bit slower than
     those made by `make-strong-eq-hash-table'.

 -- procedure: make-string-hash-table [initial-size]
     Returns a newly allocated hash table that accepts character
     strings as keys, and compares them with `string=?'.  The keys are
     held strongly.

   The next two procedures are used to create new hash-table
constructors.  All of the above hash table constructors, with the
exception of `make-eqv-hash-table', could have been created by calls to
these "constructor-constructors"; see the examples below.

 -- procedure: strong-hash-table/constructor key-hash key=?
          [rehash-after-gc?]
 -- procedure: weak-hash-table/constructor key-hash key=?
          [rehash-after-gc?]
     Each of these procedures accepts two arguments and returns a
     hash-table constructor.  The KEY=? argument is an equivalence
     predicate for the keys of the hash table.  The KEY-HASH argument
     is a procedure that computes a hash number.  Specifically,
     KEY-HASH accepts two arguments, a key and an exact positive
     integer (the "modulus"), and returns an exact non-negative integer
     that is less than the modulus.

     The optional argument REHASH-AFTER-GC?, if true, says that the
     values returned by KEY-HASH might change after a garbage
     collection.  If so, the hash-table implementation arranges for the
     table to be rehashed when necessary.  (*Note Address Hashing::, for
     information about hash procedures that have this property.)
     Otherwise, it is assumed that KEY-HASH always returns the same
     value for the same arguments.  The default value of this argument
     is `#f'.

     The constructors returned by `strong-hash-table/constructor' make
     hash tables that hold their keys strongly.  The constructors
     returned by `weak-hash-table/constructor' make hash tables that
     hold their keys weakly.

   Some examples showing how some standard hash-table constructors
could have been defined:

     (define make-weak-eq-hash-table
       (weak-hash-table/constructor eq-hash-mod eq? #t))

     (define make-equal-hash-table
       (strong-hash-table/constructor equal-hash-mod equal? #t))

     (define make-string-hash-table
       (strong-hash-table/constructor string-hash-mod string=? #f))

   The following procedure is sometimes useful in conjunction with weak
hash tables.  Normally it is not needed, because such hash tables clean
themselves automatically as they are used.

 -- procedure: hash-table/clean! hash-table
     If HASH-TABLE is a type of hash table that holds its KEYs weakly,
     this procedure recovers any space that was being used to record
     associations for objects that have been reclaimed by the garbage
     collector.  Otherwise, this procedure does nothing.  In either
     case, it returns an unspecified result.


File: mit-scheme-ref.info,  Node: Basic Hash Table Operations,  Next: Resizing of Hash Tables,  Prev: Construction of Hash Tables,  Up: Hash Tables

11.4.2 Basic Hash Table Operations
----------------------------------

The procedures described in this section are the basic operations on
hash tables.  They provide the functionality most often needed by
programmers.  Subsequent sections describe other operations that provide
additional functionality needed by some applications.

 -- procedure: hash-table? object
     Returns `#t' if OBJECT is a hash table, otherwise returns `#f'.

 -- procedure: hash-table/put! hash-table key datum
     Associates DATUM with KEY in HASH-TABLE and returns an unspecified
     result.  The average time required by this operation is bounded by
     a constant.

 -- procedure: hash-table/get hash-table key default
     Returns the datum associated with KEY in HASH-TABLE.  If there is
     no association for KEY, DEFAULT is returned.  The average time
     required by this operation is bounded by a constant.

 -- procedure: hash-table/remove! hash-table key
     If HASH-TABLE has an association for KEY, removes it.  Returns an
     unspecified result.  The average time required by this operation
     is bounded by a constant.

 -- procedure: hash-table/clear! hash-table
     Removes all associations in HASH-TABLE and returns an unspecified
     result.  The average and worst-case times required by this
     operation are bounded by a constant.

 -- procedure: hash-table/count hash-table
     Returns the number of associations in HASH-TABLE as an exact
     non-negative integer.  If HASH-TABLE holds its keys weakly, this
     is a conservative upper bound that may count some associations
     whose keys have recently been reclaimed by the garbage collector.
     The average and worst-case times required by this operation are
     bounded by a constant.

 -- procedure: hash-table->alist hash-table
     Returns the contents of HASH-TABLE as a newly allocated alist.
     Each element of the alist is a pair `(KEY . DATUM)' where KEY is
     one of the keys of HASH-TABLE, and DATUM is its associated datum.
     The average and worst-case times required by this operation are
     linear in the number of associations in the table.

 -- procedure: hash-table/key-list hash-table
     Returns a newly allocated list of the keys in HASH-TABLE.  The
     average and worst-case times required by this operation are linear
     in the number of associations in the table.

 -- procedure: hash-table/datum-list hash-table
     Returns a newly allocated list of the datums in HASH-TABLE.  Each
     element of the list corresponds to one of the associations in
     HASH-TABLE; if the table contains multiple associations with the
     same datum, so will this list.  The average and worst-case times
     required by this operation are linear in the number of
     associations in the table.

 -- procedure: hash-table/for-each hash-table procedure
     PROCEDURE must be a procedure of two arguments.  Invokes PROCEDURE
     once for each association in HASH-TABLE, passing the association's
     KEY and DATUM as arguments, in that order.  Returns an unspecified
     result.  PROCEDURE must not modify HASH-TABLE, with one exception:
     it is permitted to call `hash-table/remove!' to remove the
     association being processed.

   The following procedure is an alternate form of `hash-table/get'
that is useful in some situations.  Usually, `hash-table/get' is
preferable because it is faster.

 -- procedure: hash-table/lookup hash-table key if-found if-not-found
     IF-FOUND must be a procedure of one argument, and IF-NOT-FOUND
     must be a procedure of no arguments.  If HASH-TABLE contains an
     association for KEY, IF-FOUND is invoked on the datum of the
     association.  Otherwise, IF-NOT-FOUND is invoked with no
     arguments.  In either case, the result yielded by the invoked
     procedure is returned as the result of `hash-table/lookup'
     (`hash-table/lookup' _reduces_ into the invoked procedure, i.e.
     calls it tail-recursively).  The average time required by this
     operation is bounded by a constant.


File: mit-scheme-ref.info,  Node: Resizing of Hash Tables,  Next: Address Hashing,  Prev: Basic Hash Table Operations,  Up: Hash Tables

11.4.3 Resizing of Hash Tables
------------------------------

Normally, hash tables automatically resize themselves according to need.
Because of this, the programmer need not be concerned with management of
the table's size.  However, some limited control over the table's size
is provided, which will be discussed below.  This discussion involves
two concepts, "usable size" and "physical size", which we will now
define.

   The "usable size" of a hash table is the number of associations that
the table can hold at a given time.  If the number of associations in
the table exceeds the usable size, the table will automatically grow,
increasing the usable size to a new value that is sufficient to hold the
associations.

   The "physical size" is an abstract measure of a hash table that
specifies how much space is allocated to hold the associations of the
table.  The physical size is always greater than or equal to the usable
size.  The physical size is not interesting in itself; it is interesting
only for its effect on the performance of the hash table.  While the
average performance of a hash-table lookup is bounded by a constant, the
worst-case performance is not.  For a table containing a given number of
associations, increasing the physical size of the table decreases the
probability that worse-than-average performance will occur.

   The physical size of a hash table is statistically related to the
number of associations.  However, it is possible to place bounds on the
physical size, and from this to estimate the amount of space used by the
table:

     (define (hash-table-space-bounds count rehash-size rehash-threshold)
       (let ((tf (/ 1 rehash-threshold)))
         (values (if (exact-integer? rehash-size)
                     (- (* count (+ 4 tf))
                        (* tf (+ rehash-size rehash-size)))
                     (* count (+ 4 (/ tf (* rehash-size rehash-size)))))
                 (* count (+ 4 tf)))))

What this formula shows is that, for a "normal" rehash size (that is,
not an exact integer), the amount of space used by the hash table is
proportional to the number of associations in the table.  The constant
of proportionality varies statistically, with the low bound being

     (+ 4 (/ (/ 1 rehash-threshold) (* rehash-size rehash-size)))

and the high bound being

     (+ 4 (/ 1 rehash-threshold))

which, for the default values of these parameters, are `4.25' and `5',
respectively.  Reducing the rehash size will tighten these bounds, but
increases the amount of time spent resizing, so you can see that the
rehash size gives some control over the time-space tradeoff of the
table.

   The programmer can control the size of a hash table by means of three
parameters:

   * Each table's INITIAL-SIZE may be specified when the table is
     created.

   * Each table has a "rehash size" that specifies how the size of the
     table is changed when it is necessary to grow or shrink the table.

   * Each table has a "rehash threshold" that specifies the relationship
     of the table's physical size to its usable size.

   If the programmer knows that the table will initially contain a
specific number of items, INITIAL-SIZE can be given when the table is
created.  If INITIAL-SIZE is an exact non-negative integer, it
specifies the initial usable size of the hash table; the table will not
change size until the number of items in the table exceeds
INITIAL-SIZE, after which automatic resizing is enabled and
INITIAL-SIZE no longer has any effect.  Otherwise, if INITIAL-SIZE is
not given or is `#f', the table is initialized to an unspecified size
and automatic resizing is immediately enabled.

   The "rehash size" specifies how much to increase the usable size of
the hash table when it becomes full.  It is either an exact positive
integer, or a real number greater than one.  If it is an integer, the
new size is the sum of the old size and the rehash size.  Otherwise, it
is a real number, and the new size is the product of the old size and
the rehash size.  Increasing the rehash size decreases the average cost
of an insertion, but increases the average amount of space used by the
table.  The rehash size of a table may be altered dynamically by the
application in order to optimize the resizing of the table; for example,
if the table will grow quickly for a known period and afterwards will
not change size, performance might be improved by using a large rehash
size during the growth phase and a small one during the static phase.
The default rehash size of a newly constructed hash table is `2.0'.

   *Warning*: The use of an exact positive integer for a rehash size is
almost always undesirable; this option is provided solely for
compatibility with the Common Lisp hash-table mechanism.  The reason for
this has to do with the time penalty for resizing the hash table.  The
time needed to resize a hash table is proportional to the number of
associations in the table.  This resizing cost is "amortized" across
the insertions required to fill the table to the point where it needs
to grow again.  If the table grows by an amount proportional to the
number of associations, then the cost of resizing and the increase in
size are both proportional to the number of associations, so the
"amortized cost" of an insertion operation is still bounded by a
constant.  However, if the table grows by a constant amount, this is
not true: the amortized cost of an insertion is not bounded by a
constant.  Thus, using a constant rehash size means that the average
cost of an insertion increases proportionally to the number of
associations in the hash table.

   The "rehash threshold" is a real number, between zero exclusive and
one inclusive, that specifies the ratio between a hash table's usable
size and its physical size.  Decreasing the rehash threshold decreases
the probability of worse-than-average insertion, deletion, and lookup
times, but increases the physical size of the table for a given usable
size.  The default rehash threshold of a newly constructed hash table is
`1'.

 -- procedure: hash-table/size hash-table
     Returns the usable size of HASH-TABLE as an exact positive
     integer.  This is the number of associations that HASH-TABLE can
     hold before it will grow.

 -- procedure: hash-table/rehash-size hash-table
     Returns the rehash size of HASH-TABLE.

 -- procedure: set-hash-table/rehash-size! hash-table x
     X must be either an exact positive integer, or a real number that
     is greater than one.  Sets the rehash size of HASH-TABLE to X and
     returns an unspecified result.  This operation adjusts the "shrink
     threshold" of the table; the table might shrink if the number of
     associations is less than the new threshold.

 -- procedure: hash-table/rehash-threshold hash-table
     Returns the rehash threshold of HASH-TABLE.

 -- procedure: set-hash-table/rehash-threshold! hash-table x
     X must be a real number between zero exclusive and one inclusive.
     Sets the rehash threshold of HASH-TABLE to X and returns an
     unspecified result.  This operation does not change the usable
     size of the table, but it usually changes the physical size of the
     table, which causes the table to be rehashed.


File: mit-scheme-ref.info,  Node: Address Hashing,  Prev: Resizing of Hash Tables,  Up: Hash Tables

11.4.4 Address Hashing
----------------------

The procedures described in this section may be used to make very
efficient key-hashing procedures for arbitrary objects.  All of these
procedures are based on "address hashing", which uses the address of an
object as its hash number.  The great advantage of address hashing is
that converting an arbitrary object to a hash number is extremely fast
and takes the same amount of time for any object.

   The disadvantage of address hashing is that the garbage collector
changes the addresses of most objects.  The hash-table implementation
compensates for this disadvantage by automatically rehashing tables that
use address hashing when garbage collections occur.  Thus, in order to
use these procedures for key hashing, it is necessary to tell the
hash-table implementation (by means of the REHASH-AFTER-GC?  argument
to the "constructor-constructor" procedure) that the hash numbers
computed by your key-hashing procedure must be recomputed after a
garbage collection.

 -- procedure: eq-hash object
 -- procedure: eqv-hash object
 -- procedure: equal-hash object
     These procedures return a hash number for OBJECT.  The result is
     always a non-negative integer, and in the case of `eq-hash', a
     non-negative fixnum.  Two objects that are equivalent according to
     `eq?', `eqv?', or `equal?', respectively, will produce the same
     hash number when passed as arguments to these procedures, provided
     that the garbage collector does not run during or between the two
     calls.

   The following procedures are the key-hashing procedures used by the
standard address-hash-based hash tables.

 -- procedure: eq-hash-mod object modulus
     This procedure is the key-hashing procedure used by
     `make-strong-eq-hash-table'.

 -- procedure: eqv-hash-mod object modulus
     This procedure is the key-hashing procedure used by
     `make-strong-eqv-hash-table'.

 -- procedure: equal-hash-mod object modulus
     This procedure is the key-hashing procedure used by
     `make-equal-hash-table'.


File: mit-scheme-ref.info,  Node: Object Hashing,  Next: Red-Black Trees,  Prev: Hash Tables,  Up: Associations

11.5 Object Hashing
===================

The MIT/GNU Scheme object-hashing facility provides a mechanism for
generating a unique hash number for an arbitrary object.  This hash
number, unlike an object's address, is unchanged by garbage collection.
The object-hashing facility is useful in conjunction with hash tables,
but it may be used for other things as well.  In particular, it is used
in the generation of the written representation for many objects (*note
Custom Output::).

   All of these procedures accept an optional argument called TABLE;
this table contains the object-integer associations.  If given, this
argument must be an object-hash table as constructed by
`hash-table/make' (see below).  If not given, a default table is used.

 -- procedure: hash object [table]
     `hash' associates an exact non-negative integer with OBJECT and
     returns that integer.  If `hash' was previously called with OBJECT
     as its argument, the integer returned is the same as was returned
     by the previous call.  `hash' guarantees that distinct objects (in
     the sense of `eq?') are associated with distinct integers.

 -- procedure: unhash k [table]
     `unhash' takes an exact non-negative integer K and returns the
     object associated with that integer.  If there is no object
     associated with K, or if the object previously associated with K
     has been reclaimed by the garbage collector, an error of type
     `condition-type:bad-range-argument' is signalled.  In other words,
     if `hash' previously returned K for some object, and that object
     has not been reclaimed, it is the value of the call to `unhash'.  

   An object that is passed to `hash' as an argument is not protected
from being reclaimed by the garbage collector.  If all other references
to that object are eliminated, the object will be reclaimed.
Subsequently calling `unhash' with the hash number of the (now
reclaimed) object will signal an error.

     (define x (cons 0 0))           =>  unspecified
     (hash x)                        =>  77
     (eqv? (hash x) (hash x))        =>  #t
     (define x 0)                    =>  unspecified
     (gc-flip)                       ;force a garbage collection
     (unhash 77)                     error-->

 -- procedure: object-hashed? object [table]
     This predicate is true if OBJECT has an associated hash number.
     Otherwise it is false.

 -- procedure: valid-hash-number? k [table]
     This predicate is true if K is the hash number associated with
     some object.  Otherwise it is false.

   The following two procedures provide a lower-level interface to the
object-hashing mechanism.

 -- procedure: object-hash object [table [insert?]]
     `object-hash' is like `hash', except that it accepts an additional
     optional argument, INSERT?.  If INSERT? is supplied and is `#f',
     `object-hash' will return an integer for OBJECT only if there is
     already an association in the table; otherwise, it will return
     `#f'.  If INSERT? is not supplied, or is not `#f', `object-hash'
     always returns an integer, creating an association in the table if
     necessary.

     `object-hash' additionally treats `#f' differently than does
     `hash'.  Calling `object-hash' with `#f' as its argument will
     return an integer that, when passed to `unhash', will signal an
     error rather than returning `#f'.  Likewise, `valid-hash-number?'
     will return `#f' for this integer.

 -- procedure: object-unhash k [table]
     `object-unhash' is like `unhash', except that when K is not
     associated with any object or was previously associated with an
     object that has been reclaimed, `object-unhash' returns `#f'.
     This means that there is an ambiguity in the value returned by
     `object-unhash': if `#f' is returned, there is no way to tell if K
     is associated with `#f' or is not associated with any object at
     all.

   Finally, this procedure makes new object-hash tables:

 -- procedure: hash-table/make
     This procedure creates and returns a new, empty object-hash table
     that is suitable for use as the optional TABLE argument to the
     above procedures.  The returned table contains no associations.


File: mit-scheme-ref.info,  Node: Red-Black Trees,  Next: Weight-Balanced Trees,  Prev: Object Hashing,  Up: Associations

11.6 Red-Black Trees
====================

Balanced binary trees are a useful data structure for maintaining large
sets of associations whose keys are ordered.  While most applications
involving large association sets should use hash tables, some
applications can benefit from the use of binary trees.  Binary trees
have two advantages over hash tables:

   * The contents of a binary tree can be converted to an alist, sorted
     by key, in time proportional to the number of associations in the
     tree.  A hash table can be converted into an unsorted alist in
     linear time; sorting it requires additional time.

   * Two binary trees can be compared for equality in linear time.  Hash
     tables, on the other hand, cannot be compared at all; they must be
     converted to alists before comparison can be done, and alist
     comparison is quadratic unless the alists are sorted.

   MIT/GNU Scheme provides an implementation of "red-black" trees.  The
red-black tree-balancing algorithm provides generally good performance
because it doesn't try to keep the tree very closely balanced.  At any
given node in the tree, one side of the node can be twice as high as the
other in the worst case.  With typical data the tree will remain fairly
well balanced anyway.

   A red-black tree takes space that is proportional to the number of
associations in the tree.  For the current implementation, the constant
of proportionality is eight words per association.

   Red-black trees hold their keys "strongly".  In other words, if a
red-black tree contains an association for a given key, that key cannot
be reclaimed by the garbage collector.

   The red-black tree implementation is a run-time-loadable option.  To
use red-black trees, execute

     (load-option 'rb-tree)
   
once before calling any of the procedures defined here.

 -- procedure: make-rb-tree key=? key<?
     This procedure creates and returns a newly allocated red-black
     tree.  The tree contains no associations.  KEY=? and KEY<? are
     predicates that compare two keys and determine whether they are
     equal to or less than one another, respectively.  For any two
     keys, at most one of these predicates is true.

 -- procedure: rb-tree? object
     Returns `#t' if OBJECT is a red-black tree, otherwise returns `#f'.

 -- procedure: rb-tree/insert! rb-tree key datum
     Associates DATUM with KEY in RB-TREE and returns an unspecified
     value.  If RB-TREE already has an association for KEY, that
     association is replaced.  The average and worst-case times
     required by this operation are proportional to the logarithm of
     the number of assocations in RB-TREE.

 -- procedure: rb-tree/lookup rb-tree key default
     Returns the datum associated with KEY in RB-TREE.  If RB-TREE
     doesn't contain an association for KEY, DEFAULT is returned.  The
     average and worst-case times required by this operation are
     proportional to the logarithm of the number of assocations in
     RB-TREE.

 -- procedure: rb-tree/delete! rb-tree key
     If RB-TREE contains an association for KEY, removes it.  Returns
     an unspecified value.  The average and worst-case times required
     by this operation are proportional to the logarithm of the number
     of assocations in RB-TREE.

 -- procedure: rb-tree->alist rb-tree
     Returns the contents of RB-TREE as a newly allocated alist.  Each
     element of the alist is a pair `(KEY . DATUM)' where KEY is one of
     the keys of RB-TREE, and DATUM is its associated datum.  The alist
     is sorted by key according to the KEY<? argument used to construct
     RB-TREE.  The time required by this operation is proportional to
     the number of associations in the tree.

 -- procedure: rb-tree/key-list rb-tree
     Returns a newly allocated list of the keys in RB-TREE.  The list
     is sorted by key according to the KEY<? argument used to construct
     RB-TREE.  The time required by this operation is proportional to
     the number of associations in the tree.

 -- procedure: rb-tree/datum-list rb-tree
     Returns a newly allocated list of the datums in RB-TREE.  Each
     element of the list corresponds to one of the associations in
     RB-TREE, so if the tree contains multiple associations with the
     same datum, so will this list.  The list is sorted by the keys of
     the associations, even though they do not appear in the result.
     The time required by this operation is proportional to the number
     of associations in the tree.

     This procedure is equivalent to:

          (lambda (rb-tree) (map cdr (rb-tree->alist rb-tree)))

 -- procedure: rb-tree/equal? rb-tree-1 rb-tree-2 datum=?
     Compares RB-TREE-1 and RB-TREE-2 for equality, returning `#t' iff
     they are equal and `#f' otherwise.  The trees must have been
     constructed with the same equality and order predicates (same in
     the sense of `eq?').  The keys of the trees are compared using the
     KEY=? predicate used to build the trees, while the datums of the
     trees are compared using the equivalence predicate DATUM=?.  The
     worst-case time required by this operation is proportional to the
     number of associations in the tree.

 -- procedure: rb-tree/empty? rb-tree
     Returns `#t' iff RB-TREE contains no associations.  Otherwise
     returns `#f'.

 -- procedure: rb-tree/size rb-tree
     Returns the number of associations in RB-TREE, an exact
     non-negative integer.  The average and worst-case times required
     by this operation are proportional to the number of associations
     in the tree.

 -- procedure: rb-tree/height rb-tree
     Returns the height of RB-TREE, an exact non-negative integer.
     This is the length of the longest path from a leaf of the tree to
     the root.  The average and worst-case times required by this
     operation are proportional to the number of associations in the
     tree.

     The returned value satisfies the following:

          (lambda (rb-tree)
            (let ((size (rb-tree/size rb-tree))
                  (lg (lambda (x) (/ (log x) (log 2)))))
              (<= (lg size)
                  (rb-tree/height rb-tree)
                  (* 2 (lg (+ size 1))))))

 -- procedure: rb-tree/copy rb-tree
     Returns a newly allocated copy of RB-TREE.  The copy is identical
     to RB-TREE in all respects, except that changes to RB-TREE do not
     affect the copy, and vice versa.  The time required by this
     operation is proportional to the number of associations in the
     tree.

 -- procedure: alist->rb-tree alist key=? key<?
     Returns a newly allocated red-black tree that contains the same
     associations as ALIST.  This procedure is equivalent to:

          (lambda (alist key=? key<?)
            (let ((tree (make-rb-tree key=? key<?)))
              (for-each (lambda (association)
                          (rb-tree/insert! tree
                                           (car association)
                                           (cdr association)))
                        alist)
              tree))

   The following operations provide access to the smallest and largest
members in a red/black tree.  They are useful for implementing priority
queues.

 -- procedure: rb-tree/min rb-tree default
     Returns the smallest key in RB-TREE, or DEFAULT if the tree is
     empty.

 -- procedure: rb-tree/min-datum rb-tree default
     Returns the datum associated with the smallest key in RB-TREE, or
     DEFAULT if the tree is empty.

 -- procedure: rb-tree/min-pair rb-tree
     Finds the smallest key in RB-TREE and returns a pair containing
     that key and its associated datum.  If the tree is empty, returns
     `#f'.

 -- procedure: rb-tree/max rb-tree default
     Returns the largest key in RB-TREE, or DEFAULT if the tree is
     empty.

 -- procedure: rb-tree/max-datum rb-tree default
     Returns the datum associated with the largest key in RB-TREE, or
     DEFAULT if the tree is empty.

 -- procedure: rb-tree/max-pair rb-tree
     Finds the largest key in RB-TREE and returns a pair containing
     that key and its associated datum.  If the tree is empty, returns
     `#f'.

 -- procedure: rb-tree/delete-min! rb-tree default
 -- procedure: rb-tree/delete-min-datum! rb-tree default
 -- procedure: rb-tree/delete-min-pair! rb-tree
 -- procedure: rb-tree/delete-max! rb-tree default
 -- procedure: rb-tree/delete-max-datum! rb-tree default
 -- procedure: rb-tree/delete-max-pair! rb-tree
     These operations are exactly like the accessors above, in that they
     return information associated with the smallest or largest key,
     except that they simultaneously delete that key.


File: mit-scheme-ref.info,  Node: Weight-Balanced Trees,  Prev: Red-Black Trees,  Up: Associations

11.7 Weight-Balanced Trees
==========================

Balanced binary trees are a useful data structure for maintaining large
sets of ordered objects or sets of associations whose keys are ordered.
MIT/GNU Scheme has a comprehensive implementation of weight-balanced
binary trees which has several advantages over the other data
structures for large aggregates:

   * In addition to the usual element-level operations like insertion,
     deletion and lookup, there is a full complement of collection-level
     operations, like set intersection, set union and subset test, all
     of which are implemented with good orders of growth in time and
     space.  This makes weight-balanced trees ideal for rapid
     prototyping of functionally derived specifications.

   * An element in a tree may be indexed by its position under the
     ordering of the keys, and the ordinal position of an element may
     be determined, both with reasonable efficiency.

   * Operations to find and remove minimum element make weight-balanced
     trees simple to use for priority queues.

   * The implementation is _functional_ rather than _imperative_.  This
     means that operations like `inserting' an association in a tree do
     not destroy the old tree, in much the same way that `(+ 1 x)'
     modifies neither the constant 1 nor the value bound to `x'.  The
     trees are referentially transparent thus the programmer need not
     worry about copying the trees.  Referential transparency allows
     space efficiency to be achieved by sharing subtrees.

   These features make weight-balanced trees suitable for a wide range
of applications, especially those that require large numbers of sets or
discrete maps.  Applications that have a few global databases and/or
concentrate on element-level operations like insertion and lookup are
probably better off using hash tables or red-black trees.

   The _size_ of a tree is the number of associations that it contains.
Weight-balanced binary trees are balanced to keep the sizes of the
subtrees of each node within a constant factor of each other.  This
ensures logarithmic times for single-path operations (like lookup and
insertion).  A weight-balanced tree takes space that is proportional to
the number of associations in the tree.  For the current
implementation, the constant of proportionality is six words per
association.

   Weight-balanced trees can be used as an implementation for either
discrete sets or discrete maps (associations).  Sets are implemented by
ignoring the datum that is associated with the key.  Under this scheme
if an association exists in the tree this indicates that the key of the
association is a member of the set.  Typically a value such as `()',
`#t' or `#f' is associated with the key.

   Many operations can be viewed as computing a result that, depending
on whether the tree arguments are thought of as sets or maps, is known
by two different names.  An example is `wt-tree/member?', which, when
regarding the tree argument as a set, computes the set membership
operation, but, when regarding the tree as a discrete map,
`wt-tree/member?' is the predicate testing if the map is defined at an
element in its domain.  Most names in this package have been chosen
based on interpreting the trees as sets, hence the name
`wt-tree/member?' rather than `wt-tree/defined-at?'.

   The weight-balanced tree implementation is a run-time-loadable
option.  To use weight-balanced trees, execute

     (load-option 'wt-tree)
   
once before calling any of the procedures defined here.

* Menu:

* Construction of Weight-Balanced Trees::
* Basic Operations on Weight-Balanced Trees::
* Advanced Operations on Weight-Balanced Trees::
* Indexing Operations on Weight-Balanced Trees::


File: mit-scheme-ref.info,  Node: Construction of Weight-Balanced Trees,  Next: Basic Operations on Weight-Balanced Trees,  Prev: Weight-Balanced Trees,  Up: Weight-Balanced Trees

11.7.1 Construction of Weight-Balanced Trees
--------------------------------------------

Binary trees require there to be a total order on the keys used to
arrange the elements in the tree.  Weight-balanced trees are organized
by _types_, where the type is an object encapsulating the ordering
relation.  Creating a tree is a two-stage process.  First a tree type
must be created from the predicate that gives the ordering.  The tree
type is then used for making trees, either empty or singleton trees or
trees from other aggregate structures like association lists.  Once
created, a tree `knows' its type and the type is used to test
compatibility between trees in operations taking two trees.  Usually a
small number of tree types are created at the beginning of a program
and used many times throughout the program's execution.

 -- procedure: make-wt-tree-type key<?
     This procedure creates and returns a new tree type based on the
     ordering predicate KEY<?.  KEY<? must be a total ordering, having
     the property that for all key values `a', `b' and `c':

          (key<? a a)                         => #f
          (and (key<? a b) (key<? b a))       => #f
          (if (and (key<? a b) (key<? b c))
              (key<? a c)
              #t)                             => #t

     Two key values are assumed to be equal if neither is less than the
     other by KEY<?.

     Each call to `make-wt-tree-type' returns a distinct value, and
     trees are only compatible if their tree types are `eq?'.  A
     consequence is that trees that are intended to be used in
     binary-tree operations must all be created with a tree type
     originating from the same call to `make-wt-tree-type'.

 -- variable: number-wt-type
     A standard tree type for trees with numeric keys.  `Number-wt-type'
     could have been defined by

          (define number-wt-type (make-wt-tree-type  <))

 -- variable: string-wt-type
     A standard tree type for trees with string keys.  `String-wt-type'
     could have been defined by

          (define string-wt-type (make-wt-tree-type  string<?))

 -- procedure: make-wt-tree wt-tree-type
     This procedure creates and returns a newly allocated
     weight-balanced tree.  The tree is empty, i.e. it contains no
     associations.  WT-TREE-TYPE is a weight-balanced tree type
     obtained by calling `make-wt-tree-type'; the returned tree has
     this type.

 -- procedure: singleton-wt-tree wt-tree-type key datum
     This procedure creates and returns a newly allocated
     weight-balanced tree.  The tree contains a single association,
     that of DATUM with KEY.  WT-TREE-TYPE is a weight-balanced tree
     type obtained by calling `make-wt-tree-type'; the returned tree
     has this type.

 -- procedure: alist->wt-tree tree-type alist
     Returns a newly allocated weight-balanced tree that contains the
     same associations as ALIST.  This procedure is equivalent to:

          (lambda (type alist)
            (let ((tree (make-wt-tree type)))
              (for-each (lambda (association)
                          (wt-tree/add! tree
                                        (car association)
                                        (cdr association)))
                        alist)
              tree))


File: mit-scheme-ref.info,  Node: Basic Operations on Weight-Balanced Trees,  Next: Advanced Operations on Weight-Balanced Trees,  Prev: Construction of Weight-Balanced Trees,  Up: Weight-Balanced Trees

11.7.2 Basic Operations on Weight-Balanced Trees
------------------------------------------------

This section describes the basic tree operations on weight-balanced
trees.  These operations are the usual tree operations for insertion,
deletion and lookup, some predicates and a procedure for determining the
number of associations in a tree.

 -- procedure: wt-tree? object
     Returns `#t' if OBJECT is a weight-balanced tree, otherwise
     returns `#f'.

 -- procedure: wt-tree/empty? wt-tree
     Returns `#t' if WT-TREE contains no associations, otherwise
     returns `#f'.

 -- procedure: wt-tree/size wt-tree
     Returns the number of associations in WT-TREE, an exact
     non-negative integer.  This operation takes constant time.

 -- procedure: wt-tree/add wt-tree key datum
     Returns a new tree containing all the associations in WT-TREE and
     the association of DATUM with KEY.  If WT-TREE already had an
     association for KEY, the new association overrides the old.  The
     average and worst-case times required by this operation are
     proportional to the logarithm of the number of associations in
     WT-TREE.

 -- procedure: wt-tree/add! wt-tree key datum
     Associates DATUM with KEY in WT-TREE and returns an unspecified
     value.  If WT-TREE already has an association for KEY, that
     association is replaced.  The average and worst-case times
     required by this operation are proportional to the logarithm of
     the number of associations in WT-TREE.

 -- procedure: wt-tree/member? key wt-tree
     Returns `#t' if WT-TREE contains an association for KEY, otherwise
     returns `#f'.  The average and worst-case times required by this
     operation are proportional to the logarithm of the number of
     associations in WT-TREE.

 -- procedure: wt-tree/lookup wt-tree key default
     Returns the datum associated with KEY in WT-TREE.  If WT-TREE
     doesn't contain an association for KEY, DEFAULT is returned.  The
     average and worst-case times required by this operation are
     proportional to the logarithm of the number of associations in
     WT-TREE.

 -- procedure: wt-tree/delete wt-tree key
     Returns a new tree containing all the associations in WT-TREE,
     except that if WT-TREE contains an association for KEY, it is
     removed from the result.  The average and worst-case times required
     by this operation are proportional to the logarithm of the number
     of associations in WT-TREE.

 -- procedure: wt-tree/delete! wt-tree key
     If WT-TREE contains an association for KEY the association is
     removed.  Returns an unspecified value.  The average and worst-case
     times required by this operation are proportional to the logarithm
     of the number of associations in WT-TREE.


File: mit-scheme-ref.info,  Node: Advanced Operations on Weight-Balanced Trees,  Next: Indexing Operations on Weight-Balanced Trees,  Prev: Basic Operations on Weight-Balanced Trees,  Up: Weight-Balanced Trees

11.7.3 Advanced Operations on Weight-Balanced Trees
---------------------------------------------------

In the following the _size_ of a tree is the number of associations
that the tree contains, and a _smaller_ tree contains fewer
associations.

 -- procedure: wt-tree/split< wt-tree bound
     Returns a new tree containing all and only the associations in
     WT-TREE that have a key that is less than BOUND in the ordering
     relation of the tree type of WT-TREE.  The average and worst-case
     times required by this operation are proportional to the logarithm
     of the size of WT-TREE.

 -- procedure: wt-tree/split> wt-tree bound
     Returns a new tree containing all and only the associations in
     WT-TREE that have a key that is greater than BOUND in the ordering
     relation of the tree type of WT-TREE.  The average and worst-case
     times required by this operation are proportional to the logarithm
     of the size of WT-TREE.

 -- procedure: wt-tree/union wt-tree-1 wt-tree-2
     Returns a new tree containing all the associations from both trees.
     This operation is asymmetric: when both trees have an association
     for the same key, the returned tree associates the datum from
     WT-TREE-2 with the key.  Thus if the trees are viewed as discrete
     maps then `wt-tree/union' computes the map override of WT-TREE-1 by
     WT-TREE-2.  If the trees are viewed as sets the result is the set
     union of the arguments.  The worst-case time required by this
     operation is proportional to the sum of the sizes of both trees.
     If the minimum key of one tree is greater than the maximum key of
     the other tree then the worst-case time required is proportional to
     the logarithm of the size of the larger tree.

 -- procedure: wt-tree/intersection wt-tree-1 wt-tree-2
     Returns a new tree containing all and only those associations from
     WT-TREE-1 that have keys appearing as the key of an association in
     WT-TREE-2.  Thus the associated data in the result are those from
     WT-TREE-1.  If the trees are being used as sets the result is the
     set intersection of the arguments.  As a discrete map operation,
     `wt-tree/intersection' computes the domain restriction of
     WT-TREE-1 to (the domain of) WT-TREE-2.  The worst-case time
     required by this operation is proportional to the sum of the sizes
     of the trees.

 -- procedure: wt-tree/difference wt-tree-1 wt-tree-2
     Returns a new tree containing all and only those associations from
     WT-TREE-1 that have keys that _do not_ appear as the key of an
     association in WT-TREE-2.  If the trees are viewed as sets the
     result is the asymmetric set difference of the arguments.  As a
     discrete map operation, it computes the domain restriction of
     WT-TREE-1 to the complement of (the domain of) WT-TREE-2.  The
     worst-case time required by this operation is proportional to the
     sum of the sizes of the trees.

 -- procedure: wt-tree/subset? wt-tree-1 wt-tree-2
     Returns `#t' iff the key of each association in WT-TREE-1 is the
     key of some association in WT-TREE-2, otherwise returns `#f'.
     Viewed as a set operation, `wt-tree/subset?' is the improper subset
     predicate.  A proper subset predicate can be constructed:

          (define (proper-subset? s1 s2)
            (and (wt-tree/subset? s1 s2)
                 (< (wt-tree/size s1) (wt-tree/size s2))))

     As a discrete map operation, `wt-tree/subset?' is the subset test
     on the domain(s) of the map(s).  In the worst-case the time
     required by this operation is proportional to the size of
     WT-TREE-1.

 -- procedure: wt-tree/set-equal? wt-tree-1 wt-tree-2
     Returns `#t' iff for every association in WT-TREE-1 there is an
     association in WT-TREE-2 that has the same key, and _vice versa_.

     Viewing the arguments as sets, `wt-tree/set-equal?' is the set
     equality predicate.  As a map operation it determines if two maps
     are defined on the same domain.

     This procedure is equivalent to

          (lambda (wt-tree-1 wt-tree-2)
            (and (wt-tree/subset? wt-tree-1 wt-tree-2
                 (wt-tree/subset? wt-tree-2 wt-tree-1)))

     In the worst case the time required by this operation is
     proportional to the size of the smaller tree.

 -- procedure: wt-tree/fold combiner initial wt-tree
     This procedure reduces WT-TREE by combining all the associations,
     using an reverse in-order traversal, so the associations are
     visited in reverse order.  COMBINER is a procedure of three
     arguments: a key, a datum and the accumulated result so far.
     Provided COMBINER takes time bounded by a constant, `wt-tree/fold'
     takes time proportional to the size of WT-TREE.

     A sorted association list can be derived simply:

          (wt-tree/fold (lambda (key datum list)
                          (cons (cons key datum) list))
                        '()
                        WT-TREE))

     The data in the associations can be summed like this:

          (wt-tree/fold (lambda (key datum sum) (+ sum datum))
                        0
                        WT-TREE)

 -- procedure: wt-tree/for-each action wt-tree
     This procedure traverses WT-TREE in order, applying ACTION to each
     association.  The associations are processed in increasing order
     of their keys.  ACTION is a procedure of two arguments that takes
     the key and datum respectively of the association.  Provided
     ACTION takes time bounded by a constant, `wt-tree/for-each' takes
     time proportional to the size of WT-TREE.  The example prints the
     tree:

          (wt-tree/for-each (lambda (key value)
                              (display (list key value)))
                            WT-TREE))

 -- procedure: wt-tree/union-merge wt-tree-1 wt-tree-2 merge
     Returns a new tree containing all the associations from both
     trees.  If both trees have an association for the same key, the
     datum associated with that key in the result tree is computed by
     applying the procedure MERGE to the key, the value from WT-TREE-1
     and the value from WT-TREE-2.  MERGE is of the form

          (lambda (KEY DATUM-1 DATUM-2) ...)

     If some key occurs only in one tree, that association will appear
     in the result tree without being processed by MERGE, so for this
     operation to make sense, either MERGE must have both a right and
     left identity that correspond to the association being absent in
     one of the trees, or some guarantee must be made, for example, all
     the keys in one tree are known to occur in the other.

     These are all reasonable procedures for MERGE

          (lambda (key val1 val2) (+ val1 val2))
          (lambda (key val1 val2) (append val1 val2))
          (lambda (key val1 val2) (wt-tree/union val1 val2))

     However, a procedure like

          (lambda (key val1 val2) (- val1 val2))

     would result in a subtraction of the data for all associations
     with keys occuring in both trees but associations with keys
     occuring in only the second tree would be copied, not negated, as
     is presumably be intent.  The programmer might ensure that this
     never happens.

     This procedure has the same time behavior as `wt-tree/union' but
     with a slightly worse constant factor.  Indeed, `wt-tree/union'
     might have been defined like this:

          (define (wt-tree/union tree1 tree2)
            (wt-tree/union-merge tree1 tree2
                                 (lambda (key val1 val2) val2)))

   The MERGE procedure takes the KEY as a parameter in case the data
are not independent of the key.


File: mit-scheme-ref.info,  Node: Indexing Operations on Weight-Balanced Trees,  Prev: Advanced Operations on Weight-Balanced Trees,  Up: Weight-Balanced Trees

11.7.4 Indexing Operations on Weight-Balanced Trees
---------------------------------------------------

Weight-balanced trees support operations that view the tree as sorted
sequence of associations.  Elements of the sequence can be accessed by
position, and the position of an element in the sequence can be
determined, both in logarthmic time.

 -- procedure: wt-tree/index wt-tree index
 -- procedure: wt-tree/index-datum wt-tree index
 -- procedure: wt-tree/index-pair wt-tree index
     Returns the 0-based INDEXth association of WT-TREE in the sorted
     sequence under the tree's ordering relation on the keys.
     `wt-tree/index' returns the INDEXth key, `wt-tree/index-datum'
     returns the datum associated with the INDEXth key and
     `wt-tree/index-pair' returns a new pair `(KEY . DATUM)' which is
     the `cons' of the INDEXth key and its datum.  The average and
     worst-case times required by this operation are proportional to
     the logarithm of the number of associations in the tree.

     These operations signal a condition of type
     `condition-type:bad-range-argument' if INDEX`<0' or if INDEX is
     greater than or equal to the number of associations in the tree.
     If the tree is empty, they signal an anonymous error.

     Indexing can be used to find the median and maximum keys in the
     tree as follows:

          median:   (wt-tree/index WT-TREE
                                   (quotient (wt-tree/size WT-TREE)
                                             2))
          maximum:  (wt-tree/index WT-TREE
                                   (- (wt-tree/size WT-TREE)
                                      1))

 -- procedure: wt-tree/rank wt-tree key
     Determines the 0-based position of KEY in the sorted sequence of
     the keys under the tree's ordering relation, or `#f' if the tree
     has no association with for KEY.  This procedure returns either an
     exact non-negative integer or `#f'.  The average and worst-case
     times required by this operation are proportional to the logarithm
     of the number of associations in the tree.

 -- procedure: wt-tree/min wt-tree
 -- procedure: wt-tree/min-datum wt-tree
 -- procedure: wt-tree/min-pair wt-tree
     Returns the association of WT-TREE that has the least key under
     the tree's ordering relation.  `wt-tree/min' returns the least key,
     `wt-tree/min-datum' returns the datum associated with the least
     key and `wt-tree/min-pair' returns a new pair `(key . datum)'
     which is the `cons' of the minimum key and its datum.  The average
     and worst-case times required by this operation are proportional
     to the logarithm of the number of associations in the tree.

     These operations signal an error if the tree is empty.  They could
     have been written

          (define (wt-tree/min tree)
            (wt-tree/index tree 0))
          (define (wt-tree/min-datum tree)
            (wt-tree/index-datum tree 0))
          (define (wt-tree/min-pair tree)
            (wt-tree/index-pair tree 0))

 -- procedure: wt-tree/delete-min wt-tree
     Returns a new tree containing all of the associations in WT-TREE
     except the association with the least key under the WT-TREE's
     ordering relation.  An error is signalled if the tree is empty.
     The average and worst-case times required by this operation are
     proportional to the logarithm of the number of associations in the
     tree.  This operation is equivalent to

          (wt-tree/delete WT-TREE (wt-tree/min WT-TREE))

 -- procedure: wt-tree/delete-min! wt-tree
     Removes the association with the least key under the WT-TREE's
     ordering relation.  An error is signalled if the tree is empty.
     The average and worst-case times required by this operation are
     proportional to the logarithm of the number of associations in the
     tree.  This operation is equivalent to

          (wt-tree/delete! WT-TREE (wt-tree/min WT-TREE))


File: mit-scheme-ref.info,  Node: Procedures,  Next: Environments,  Prev: Associations,  Up: Top

12 Procedures
*************

Procedures are created by evaluating `lambda' expressions (*note Lambda
Expressions::); the `lambda' may either be explicit or may be implicit
as in a "procedure `define'" (*note Definitions::).  Also there are
special built-in procedures, called "primitive procedures", such as
`car'; these procedures are not written in Scheme but in the language
used to implement the Scheme system.  MIT/GNU Scheme also provides
"application hooks", which support the construction of data structures
that act like procedures.

   In MIT/GNU Scheme, the written representation of a procedure tells
you the type of the procedure (compiled, interpreted, or primitive):

     pp
          =>  #[compiled-procedure 56 ("pp" #x2) #x10 #x307578]
     (lambda (x) x)
          =>  #[compound-procedure 57]
     (define (foo x) x)
     foo
          =>  #[compound-procedure 58 foo]
     car
          =>  #[primitive-procedure car]
     (call-with-current-continuation (lambda (x) x))
          =>  #[continuation 59]

Note that interpreted procedures are called "compound" procedures
(strictly speaking, compiled procedures are also compound procedures).
The written representation makes this distinction for historical
reasons, and may eventually change.

* Menu:

* Procedure Operations::
* Arity::
* Primitive Procedures::
* Continuations::
* Application Hooks::
* Generic Dispatch::


File: mit-scheme-ref.info,  Node: Procedure Operations,  Next: Arity,  Prev: Procedures,  Up: Procedures

12.1 Procedure Operations
=========================

 -- procedure: apply procedure object object ...
     Calls PROCEDURE with the elements of the following list as
     arguments:

          (cons* OBJECT OBJECT ...)

     The initial OBJECTs may be any objects, but the last OBJECT (there
     must be at least one OBJECT) must be a list.

          (apply + (list 3 4 5 6))                =>  18
          (apply + 3 4 '(5 6))                    =>  18

          (define compose
            (lambda (f g)
              (lambda args
                (f (apply g args)))))
          ((compose sqrt *) 12 75)                =>  30

 -- procedure: procedure? object
     Returns `#t' if OBJECT is a procedure; otherwise returns `#f'.  If
     `#t' is returned, exactly one of the following predicates is
     satisfied by OBJECT: `compiled-procedure?', `compound-procedure?',
     or `primitive-procedure?'.

 -- procedure: compiled-procedure? object
     Returns `#t' if OBJECT is a compiled procedure; otherwise returns
     `#f'.

 -- procedure: compound-procedure? object
     Returns `#t' if OBJECT is a compound (i.e. interpreted) procedure;
     otherwise returns `#f'.

 -- procedure: primitive-procedure? object
     Returns `#t' if OBJECT is a primitive procedure; otherwise returns
     `#f'.

 -- procedure: procedure-environment procedure
     Returns the closing environment of PROCEDURE.  Signals an error if
     PROCEDURE is a primitive procedure, or if PROCEDURE is a compiled
     procedure for which the debugging information is unavailable.


File: mit-scheme-ref.info,  Node: Arity,  Next: Primitive Procedures,  Prev: Procedure Operations,  Up: Procedures

12.2 Arity
==========

Each procedure has an "arity", which is the minimum and (optionally)
maximum number of arguments that it will accept.  MIT/GNU Scheme
provides an abstraction that represents arity, and tests for the
apparent arity of a procedure.

   Arity objects come in two forms: the simple form, an exact
non-negative integer, represents a fixed number of arguments.  The
general form is a pair whose `car' represents the minimum number of
arguments and whose `cdr' is the maximum number of arguments.

 -- procedure: make-procedure-arity min [max [simple-ok?]]
     Returns an arity object made from MIN and MAX.  MIN must be an
     exact non-negative integer.  MAX must be an exact non-negative
     integer at least as large as MIN.  Alternatively, MAX may be
     omitted or given as `#f', which represents an arity with no upper
     bound.

     If SIMPLE-OK? is true, the returned arity is in the simple form
     (an exact non-negative integer) when possible, and otherwise is
     always in the general form.  SIMPLE-OK? defaults to `#f'.

 -- procedure: procedure-arity? object
     Returns `#t' if OBJECT is an arity object, and `#f' otherwise.

 -- procedure: guarantee-procedure-arity object caller
     Signals an error if OBJECT is not an arity object.  CALLER is a
     symbol that is printed as part of the error message and is
     intended to be the name of the procedure where the error occurs.

 -- procedure: procedure-arity-min arity
 -- procedure: procedure-arity-max arity
     Return the lower and upper bounds of ARITY, respectively.

   The following procedures test for the apparent arity of a procedure.
The results of the test may be less restrictive than the effect of
calling the procedure.  In other words, these procedures may indicate
that the procedure will accept a given number of arguments, but if you
call the procedure it may signal a
`condition-type:wrong-number-of-arguments' error.  For example, here is
a procedure that appears to accept any number of arguments, but when
called will signal an error if the number of arguments is not one:

     (lambda arguments (apply car arguments))

 -- procedure: procedure-arity procedure
     Returns the arity that PROCEDURE accepts.  The result may be in
     either simple or general form.

          (procedure-arity (lambda () 3))         =>  (0 . 0)
          (procedure-arity (lambda (x) x))        =>  (1 . 1)
          (procedure-arity car)                   =>  (1 . 1)
          (procedure-arity (lambda x x))          =>  (0 . #f)
          (procedure-arity (lambda (x . y) x))    =>  (1 . #f)
          (procedure-arity (lambda (x #!optional y) x))
                                                  =>  (1 . 2)

 -- procedure: procedure-arity-valid? procedure arity
     Returns `#t' if PROCEDURE accepts ARITY, and `#f' otherwise.

 -- procedure: procedure-of-arity? object arity
     Returns `#t' if OBJECT is a procedure that accepts ARITY, and `#f'
     otherwise.  Equivalent to:

          (and (procedure? OBJECT)
               (procedure-arity-valid? OBJECT ARITY))

 -- procedure: guarantee-procedure-of-arity object arity caller
     Signals an error if OBJECT is not a procedure accepting ARITY.
     CALLER is a symbol that is printed as part of the error message
     and is intended to be the name of the procedure where the error
     occurs.

 -- procedure: thunk? object
     Returns `#t' if OBJECT is a procedure that accepts zero arguments,
     and `#f' otherwise.  Equivalent to:

          (procedure-of-arity? OBJECT 0)

 -- procedure: guarantee-thunk object caller
     Signals an error if OBJECT is not a procedure accepting zero
     arguments.  CALLER is a symbol that is printed as part of the
     error message and is intended to be the name of the procedure where
     the error occurs.


File: mit-scheme-ref.info,  Node: Primitive Procedures,  Next: Continuations,  Prev: Arity,  Up: Procedures

12.3 Primitive Procedures
=========================

 -- procedure: make-primitive-procedure name [arity]
     NAME must be a symbol.  ARITY must be an exact non-negative
     integer, `-1', `#f', or `#t'; if not supplied it defaults to `#f'.
     Returns the primitive procedure called NAME.  May perform further
     actions depending on ARITY:

    `#f'
          If the primitive procedure is not implemented, signals an
          error.

    `#t'
          If the primitive procedure is not implemented, returns `#f'.

    integer
          If the primitive procedure is implemented, signals an error
          if its arity is not equal to ARITY.  If the primitive
          procedure is not implemented, returns an unimplemented
          primitive procedure object that accepts ARITY arguments.  An
          ARITY of `-1' means it accepts any number of arguments.

 -- procedure: primitive-procedure-name primitive-procedure
     Returns the name of PRIMITIVE-PROCEDURE, a symbol.

          (primitive-procedure-name car)          =>  car

 -- procedure: implemented-primitive-procedure? primitive-procedure
     Returns `#t' if PRIMITIVE-PROCEDURE is implemented; otherwise
     returns `#f'.  Useful because the code that implements a particular
     primitive procedure is not necessarily linked into the executable
     Scheme program.


File: mit-scheme-ref.info,  Node: Continuations,  Next: Application Hooks,  Prev: Primitive Procedures,  Up: Procedures

12.4 Continuations
==================

 -- procedure: call-with-current-continuation procedure
     PROCEDURE must be a procedure of one argument.  Packages up the
     current continuation (see below) as an "escape procedure" and
     passes it as an argument to PROCEDURE.  The escape procedure is a
     Scheme procedure of one argument that, if it is later passed a
     value, will ignore whatever continuation is in effect at that
     later time and will give the value instead to the continuation
     that was in effect when the escape procedure was created.  The
     escape procedure created by `call-with-current-continuation' has
     unlimited extent just like any other procedure in Scheme.  It may
     be stored in variables or data structures and may be called as
     many times as desired.

     The following examples show only the most common uses of this
     procedure.  If all real programs were as simple as these examples,
     there would be no need for a procedure with the power of
     `call-with-current-continuation'.

          (call-with-current-continuation
            (lambda (exit)
              (for-each (lambda (x)
                          (if (negative? x)
                              (exit x)))
                        '(54 0 37 -3 245 19))
              #t))                                =>  -3

          (define list-length
            (lambda (obj)
              (call-with-current-continuation
                (lambda (return)
                  (letrec ((r
                            (lambda (obj)
                              (cond ((null? obj) 0)
                                    ((pair? obj) (+ (r (cdr obj)) 1))
                                    (else (return #f))))))
                    (r obj))))))
          (list-length '(1 2 3 4))                =>  4
          (list-length '(a b . c))                =>  #f

     A common use of `call-with-current-continuation' is for structured,
     non-local exits from loops or procedure bodies, but in fact
     `call-with-current-continuation' is quite useful for implementing a
     wide variety of advanced control structures.

     Whenever a Scheme expression is evaluated a continuation exists
     that wants the result of the expression.  The continuation
     represents an entire (default) future for the computation.  If the
     expression is evaluated at top level, for example, the
     continuation will take the result, print it on the screen, prompt
     for the next input, evaluate it, and so on forever.  Most of the
     time the continuation includes actions specified by user code, as
     in a continuation that will take the result, multiply it by the
     value stored in a local variable, add seven, and give the answer
     to the top-level continuation to be printed.  Normally these
     ubiquitous continuations are hidden behind the scenes and
     programmers don't think much about them.  On the rare occasions
     that you may need to deal explicitly with continuations,
     `call-with-current-continuation' lets you do so by creating a
     procedure that acts just like the current continuation.

 -- procedure: continuation? object
     Returns `#t' if OBJECT is a continuation; otherwise returns `#f'.

 -- procedure: within-continuation continuation thunk
     THUNK must be a procedure of no arguments.  Conceptually,
     `within-continuation' invokes CONTINUATION on the result of
     invoking THUNK, but THUNK is executed in the dynamic context of
     CONTINUATION.  In other words, the "current" continuation is
     abandoned before THUNK is invoked.

 -- procedure: dynamic-wind before thunk after
     Calls THUNK without arguments, returning the result(s) of this
     call.  BEFORE and AFTER are called, also without arguments, as
     required by the following rules (note that in the absence of calls
     to continuations captured using `call-with-current-continuation'
     the three arguments are called once each, in order).  BEFORE is
     called whenever execution enters the dynamic extent of the call to
     THUNK and AFTER is called whenever it exits that dynamic extent.
     The dynamic extent of a procedure call is the period between when
     the call is initiated and when it returns.  In Scheme, because of
     `call-with-current-continuation', the dynamic extent of a call may
     not be a single, connected time period.  It is defined as follows:

        * The dynamic extent is entered when execution of the body of
          the called procedure begins.

        * The dynamic extent is also entered when execution is not
          within the dynamic extent and a continuation is invoked that
          was captured (using `call-with-current-continuation') during
          the dynamic extent.

        * It is exited when the called procedure returns.

        * It is also exited when execution is within the dynamic extent
          and a continuation is invoked that was captured while not
          within the dynamic extent.

     If a second call to `dynamic-wind' occurs within the dynamic extent
     of the call to THUNK and then a continuation is invoked in such a
     way that the AFTERs from these two invocations of `dynamic-wind'
     are both to be called, then the AFTER associated with the second
     (inner) call to `dynamic-wind' is called first.

     If a second call to `dynamic-wind' occurs within the dynamic extent
     of the call to THUNK and then a continuation is invoked in such a
     way that the BEFOREs from these two invocations of `dynamic-wind'
     are both to be called, then the BEFORE associated with the first
     (outer) call to `dynamic-wind' is called first.

     If invoking a continuation requires calling the BEFORE from one
     call to `dynamic-wind' and the AFTER from another, then the AFTER
     is called first.

     The effect of using a captured continuation to enter or exit the
     dynamic extent of a call to BEFORE or AFTER is undefined.

          (let ((path '())
                (c #f))
            (let ((add (lambda (s)
                         (set! path (cons s path)))))
              (dynamic-wind
                (lambda () (add 'connect))
                (lambda ()
                  (add (call-with-current-continuation
                         (lambda (c0)
                           (set! c c0)
                           'talk1))))
                (lambda () (add 'disconnect)))
              (if (< (length path) 4)
                  (c 'talk2)
                  (reverse path))))

          => (connect talk1 disconnect connect talk2 disconnect)

   The following two procedures support multiple values.

 -- procedure: call-with-values thunk procedure
     THUNK must be a procedure of no arguments, and PROCEDURE must be a
     procedure.  THUNK is invoked with a continuation that expects to
     receive multiple values; specifically, the continuation expects to
     receive the same number of values that PROCEDURE accepts as
     arguments.  THUNK must return multiple values using the `values'
     procedure.  Then PROCEDURE is called with the multiple values as
     its arguments.  The result yielded by PROCEDURE is returned as the
     result of `call-with-values'.

 -- procedure: values object ...
     Returns multiple values.  The continuation in effect when this
     procedure is called must be a multiple-value continuation that was
     created by `call-with-values'.  Furthermore it must accept as many
     values as there are OBJECTs.


File: mit-scheme-ref.info,  Node: Application Hooks,  Next: Generic Dispatch,  Prev: Continuations,  Up: Procedures

12.5 Application Hooks
======================

"Application hooks" are objects that can be applied like procedures.
Each application hook has two parts: a "procedure" that specifies what
to do when the application hook is applied, and an arbitrary object,
called "extra".  Often the procedure uses the extra object to determine
what to do.

   There are two kinds of application hooks, which differ in what
arguments are passed to the procedure.  When an "apply hook" is
applied, the procedure is passed exactly the same arguments that were
passed to the apply hook.  When an "entity" is applied, the entity
itself is passed as the first argument, followed by the other arguments
that were passed to the entity.

   Both apply hooks and entities satisfy the predicate `procedure?'.
Each satisfies either `compiled-procedure?', `compound-procedure?', or
`primitive-procedure?', depending on its procedure component.  An apply
hook is considered to accept the same number of arguments as its
procedure, while an entity is considered to accept one less argument
than its procedure.

 -- procedure: make-apply-hook procedure object
     Returns a newly allocated apply hook with a procedure component of
     PROCEDURE and an extra component of OBJECT.

 -- procedure: apply-hook? object
     Returns `#t' if OBJECT is an apply hook; otherwise returns `#f'.

 -- procedure: apply-hook-procedure apply-hook
     Returns the procedure component of APPLY-HOOK.

 -- procedure: set-apply-hook-procedure! apply-hook procedure
     Changes the procedure component of APPLY-HOOK to be PROCEDURE.
     Returns an unspecified value.

 -- procedure: apply-hook-extra apply-hook
     Returns the extra component of APPLY-HOOK.

 -- procedure: set-apply-hook-extra! apply-hook object
     Changes the extra component of APPLY-HOOK to be OBJECT.  Returns
     an unspecified value.

 -- procedure: make-entity procedure object
     Returns a newly allocated entity with a procedure component of
     PROCEDURE and an extra component of OBJECT.

 -- procedure: entity? object
     Returns `#t' if OBJECT is an entity; otherwise returns `#f'.

 -- procedure: entity-procedure entity
     Returns the procedure component of ENTITY.

 -- procedure: set-entity-procedure! entity procedure
     Changes the procedure component of ENTITY to be PROCEDURE.
     Returns an unspecified value.

 -- procedure: entity-extra entity
     Returns the extra component of ENTITY.

 -- procedure: set-entity-extra! entity object
     Changes the extra component of ENTITY to be OBJECT.  Returns an
     unspecified value.


File: mit-scheme-ref.info,  Node: Generic Dispatch,  Prev: Application Hooks,  Up: Procedures

12.6 Generic Dispatch
=====================

MIT/GNU Scheme provides a generic dispatch mechanism that can choose an
action to take based on the types of a set of objects.  Performance is
guaranteed by the use of a hash-based method cache.

   This is _not_ an object-oriented programming system, although it can
provide the basis for such systems.  The difference is that the generic
dispatch doesn't have any model for the relationship between object
types.  Instead, there is a flat space of types and methods are
selected by procedural examination of the given operand types.

* Menu:

* Generic Procedures::
* Method Generators::
* Dispatch Tags::


File: mit-scheme-ref.info,  Node: Generic Procedures,  Next: Method Generators,  Prev: Generic Dispatch,  Up: Generic Dispatch

12.6.1 Generic Procedures
-------------------------

The core of the dispatch mechanism is the "generic procedure".  This is
a procedure that is called in the usual way, but which dispatches to a
particular "method" based on the types of its arguments.

 -- procedure: make-generic-procedure arity [name]
     Returns a new generic procedure accepting ARITY.  ARITY must
     specify a minimum of one argument.

     NAME is used for debugging: it is a symbol that has no role in the
     semantics of the generic procedure.  NAME may be `#f' to indicate
     that the generic procedure is anonymous.  If NAME is not
     specified, it defaults to `#f'.

     Examples:

          (define foo-bar (make-generic-procedure 2 'bar))

          (define foo-baz (make-generic-procedure '(1 . 2) 'foo-baz))

          (define foo-mum (make-generic-procedure '(1 . #f)))

 -- procedure: generic-procedure? object
     Returns `#t' if OBJECT is a generic procedure, and `#f' otherwise.

 -- procedure: guarantee-generic-procedure object caller
     Signals an error if OBJECT is not a generic procedure.  CALLER is
     a symbol that is printed as part of the error message and is
     intended to be the name of the procedure where the error occurs.

 -- procedure: generic-procedure-arity generic
     Returns the arity of GENERIC, as given to `make-generic-procedure'.

 -- procedure: generic-procedure-name generic
     Returns the name of GENERIC, as given to `make-generic-procedure'.

 -- procedure: generic-procedure-applicable? generic operands
     Returns `#t' if GENERIC is applicable to OPERANDS (which must be a
     list of objects), and `#f' otherwise.

 -- condition type: condition-type:no-applicable-methods operator
          operands
     This condition type is signalled when a generic procedure is
     applied and there are no applicable methods for the given
     operands.  The condition's OPERATOR field contains the generic
     procedure and the OPERANDS field contains the given operands.

 -- condition type: condition-type:extra-applicable-methods operator
          operands
     This condition type is signalled when a generic procedure is
     applied and there are more than one applicable methods for the
     given operands.  The condition's OPERATOR field contains the
     generic procedure and the OPERANDS field contains the given
     operands.


File: mit-scheme-ref.info,  Node: Method Generators,  Next: Dispatch Tags,  Prev: Generic Procedures,  Up: Generic Dispatch

12.6.2 Method Generators
------------------------

Generic-procedure methods are dynamically chosen by "generators", which
are procedures of two arguments.  Each generic procedure has a set of
associated generators.  Whenever the procedure is applied, each
associated generator is applied to two arguments: the generic procedure
and a list of the dispatch tags for the operands.  The return value
from the generator is either a "method" (a procedure accepting that
number of arguments) or `#f'.  In order for the application to succeed,
exactly one of the generic procedure's generators must return a method.

   Once a method has been chosen, it is cached.  A subsequent call to
the generic procedure with operands of the same types will reuse that
cached method.  Consequently, it is important that generators be
"functional": they must always compute the same value from the same
arguments.

 -- procedure: add-generic-procedure-generator generic generator
     Adds GENERATOR to GENERIC's set of generators and returns an
     unspecified value.

 -- procedure: remove-generic-procedure-generator generic generator
     Removes GENERATOR from GENERIC's set of generators and returns an
     unspecified value.

 -- procedure: remove-generic-procedure-generators generic tags
     Calls each of GENERIC's set of generators on TAGS and removes each
     generator that returns a method.  Returns an unspecified value.

 -- procedure: generic-procedure-generator-list generic
     Returns a list of GENERIC's generators.

   As a convenience, each generic procedure can have a "default
generator", which is called only when all of the other generators have
returned `#f'.  When created, a generic procedure has no default
generator.

 -- procedure: generic-procedure-default-generator generic
     Returns GENERIC's default generator.

 -- procedure: set-generic-procedure-default-generator! generic
          generator
     Sets GENERIC's default generator to GENERATOR and returns an
     unspecified value.


File: mit-scheme-ref.info,  Node: Dispatch Tags,  Prev: Method Generators,  Up: Generic Dispatch

12.6.3 Dispatch Tags
--------------------

A dispatch tag is an object that represents the "type" of an object,
for the purposes of generic dispatch.  Every object has an associated
dispatch tag.  Built-in objects like pairs or booleans have predefined
tags, while dynamically typed objects like records have tags that are
created as needed.

 -- procedure: dispatch-tag object
     Returns the dispatch tag for OBJECT.

          (dispatch-tag #f)       => #[dispatch-tag 17 (boolean)]
          (dispatch-tag #t)       => #[dispatch-tag 17 (boolean)]
          (dispatch-tag (list))   => #[dispatch-tag 18 (null)]
          (dispatch-tag (list 3)) => #[dispatch-tag 19 (pair list)]

 -- procedure: built-in-dispatch-tag name
     Returns the built-in dispatch tag called NAME.  NAME must be a
     symbol that is the name of a known built-in dispatch tag.

          (built-in-dispatch-tag 'boolean) => #[dispatch-tag 17 (boolean)]
          (built-in-dispatch-tag 'null)    => #[dispatch-tag 18 (null)]
          (built-in-dispatch-tag 'pair)    => #[dispatch-tag 19 (pair list)]
          (built-in-dispatch-tag 'list)    => #[dispatch-tag 19 (pair list)]

 -- procedure: built-in-dispatch-tags
     Returns a list of the built-in dispatch tags.

 -- procedure: record-type-dispatch-tag record-type
     Returns the dispatch tag associate with RECORD-TYPE.  See *Note
     Records::, for more information about record types.

 -- procedure: dispatch-tag? object
     Returns `#t' if OBJECT is a dispatch tag, and `#f' otherwise.

 -- procedure: guarantee-dispatch-tag object caller
     Signals an error if OBJECT is not a dispatch tag.  CALLER is a
     symbol that is printed as part of the error message and is
     intended to be the name of the procedure where the error occurs.


File: mit-scheme-ref.info,  Node: Environments,  Next: Input/Output,  Prev: Procedures,  Up: Top

13 Environments
***************

* Menu:

* Environment Operations::
* Environment Variables::
* REPL Environment::
* Top-level Environments::


File: mit-scheme-ref.info,  Node: Environment Operations,  Next: Environment Variables,  Prev: Environments,  Up: Environments

13.1 Environment Operations
===========================

Environments are first-class objects in MIT/GNU Scheme.  An environment
consists of some bindings and possibly a parent environment, from which
other bindings are inherited.  The operations in this section reveal the
frame-like structure of environments by permitting you to examine the
bindings of a particular environment separately from those of its
parent.

   There are several types of bindings that can occur in an environment.
The most common is the simple variable binding, which associates a value
(any Scheme object) with an identifier (a symbol).  A variable binding
can also be "unassigned", which means that it has no value.  An
unassigned variable is bound, in that is will shadow other bindings of
the same name in ancestor environments, but a reference to that variable
will signal an error of type `condition-type:unassigned-variable'.  An
unassigned variable can be "assigned" (using `set!' or
`environment-assign!') to give it a value.

   In addition to variable bindings, an environment can also have
"keyword bindings".  A keyword binding associates a syntactic keyword
(usually a macro transformer) with an identifier.  Keyword bindings are
special in that they are considered "bound", but ordinary variable
references don't work on them.  So an attempt to reference or assign a
keyword binding results in an error of type
`condition-type:macro-binding'.  However, keyword bindings can be
redefined using `define' or `environment-define'.

 -- procedure: environment? object
     Returns `#t' if OBJECT is an environment; otherwise returns `#f'.

 -- procedure: environment-has-parent? environment
     Returns `#t' if ENVIRONMENT has a parent environment; otherwise
     returns `#f'.

 -- procedure: environment-parent environment
     Returns the parent environment of ENVIRONMENT.  It is an error if
     ENVIRONMENT has no parent.

 -- procedure: environment-bound-names environment
     Returns a newly allocated list of the names (symbols) that are
     bound by ENVIRONMENT.  This does not include the names that are
     bound by the parent environment of ENVIRONMENT.  It does include
     names that are unassigned or keywords in ENVIRONMENT.

 -- procedure: environment-macro-names environment
     Returns a newly allocated list of the names (symbols) that are
     bound to syntactic keywords in ENVIRONMENT.

 -- procedure: environment-bindings environment
     Returns a newly allocated list of the bindings of ENVIRONMENT;
     does not include the bindings of the parent environment.  Each
     element of this list takes one of two forms: `(SYMBOL)' indicates
     that SYMBOL is bound but unassigned, while `(SYMBOL OBJECT)'
     indicates that SYMBOL is bound, and its value is OBJECT.

 -- procedure: environment-reference-type environment symbol
     Returns a symbol describing the "reference type" of SYMBOL in
     ENVIRONMENT or one of its ancestor environments.  The result is
     one of the following:

    `normal'
          means SYMBOL is a variable binding with a normal value.

    `unassigned'
          means SYMBOL is a variable binding with no value.

    `macro'
          means SYMBOL is a keyword binding.

    `unbound'
          means SYMBOL has no associated binding.

 -- procedure: environment-bound? environment symbol
     Returns `#t' if SYMBOL is bound in ENVIRONMENT or one of its
     ancestor environments; otherwise returns `#f'.  This is equivalent
     to

          (not (eq? 'unbound
                    (environment-reference-type ENVIRONMENT SYMBOL)))

 -- procedure: environment-assigned? environment symbol
     Returns `#t' if SYMBOL is bound in ENVIRONMENT or one of its
     ancestor environments, and has a normal value.  Returns `#f' if it
     is bound but unassigned.  Signals an error if it is unbound or is
     bound to a keyword.

 -- procedure: environment-lookup environment symbol
     SYMBOL must be bound to a normal value in ENVIRONMENT or one of
     its ancestor environments.  Returns the value to which it is bound.
     Signals an error if unbound, unassigned, or a keyword.

 -- procedure: environment-lookup-macro environment symbol
     If SYMBOL is a keyword binding in ENVIRONMENT or one of its
     ancestor environments, returns the value of the binding.
     Otherwise, returns `#f'.  Does not signal any errors other than
     argument-type errors.

 -- procedure: environment-assignable? environment symbol
     SYMBOL must be bound in ENVIRONMENT or one of its ancestor
     environments.  Returns `#t' if the binding may be modified by side
     effect.

 -- procedure: environment-assign! environment symbol object
     SYMBOL must be bound in ENVIRONMENT or one of its ancestor
     environments, and must be assignable.  Modifies the binding to have
     OBJECT as its value, and returns an unspecified result.

 -- procedure: environment-definable? environment symbol
     Returns `#t' if SYMBOL is definable in ENVIRONMENT, and `#f'
     otherwise.  At present, this is false for environments generated
     by application of compiled procedures, and true for all other
     environments.

 -- procedure: environment-define environment symbol object
     Defines SYMBOL to be bound to OBJECT in ENVIRONMENT, and returns
     an unspecified value.  Signals an error if SYMBOL isn't definable
     in ENVIRONMENT.

 -- procedure: environment-define-macro environment symbol transformer
     Defines SYMBOL to be a keyword bound to TRANSFORMER in
     ENVIRONMENT, and returns an unspecified value.  Signals an error
     if SYMBOL isn't definable in ENVIRONMENT.  The type of TRANSFORMER
     is defined by the syntax engine and is not checked by this
     procedure.  If the type is incorrect this will subsequently signal
     an error during syntax expansion.

 -- procedure: eval expression environment
     Evaluates EXPRESSION, a list-structure representation (sometimes
     called s-expression representation) of a Scheme expression, in
     ENVIRONMENT.  You rarely need `eval' in ordinary programs; it is
     useful mostly for evaluating expressions that have been created "on
     the fly" by a program.  `eval' is relatively expensive because it
     must convert EXPRESSION to an internal form before it is executed.

          (define foo (list '+ 1 2))
          (eval foo (the-environment))            =>  3


File: mit-scheme-ref.info,  Node: Environment Variables,  Next: REPL Environment,  Prev: Environment Operations,  Up: Environments

13.2 Environment Variables
==========================

The `user-initial-environment' is where the top-level read-eval-print
(REP) loop evaluates expressions and binds definitions.  It is a child
of `system-global-environment', which is where all of the Scheme system
definitions are bound.  All of the bindings in
`system-global-environment' are available when the current environment
is `user-initial-environment'.  However, any new bindings that you
create in the REP loop (with `define' forms or by loading files
containing `define' forms) occur in `user-initial-environment'.

 -- variable: system-global-environment
     The variable `system-global-environment' is bound to the
     distinguished environment that's the ancestor of most other
     environments (except for those created by
     `make-root-top-level-environment').  It is the parent environment
     of `user-initial-environment'.  Primitives, system procedures, and
     most syntactic keywords are bound (and sometimes closed) in this
     environment.

 -- variable: user-initial-environment
     The variable `user-initial-environment' is bound to the default
     environment in which typed expressions are evaluated by the
     top-level REP loop.

     Although all bindings in `system-global-environment' are visible to
     the REP loop, definitions that are typed at, or loaded by, the REP
     loop occur in the `user-initial-environment'.  This is partly a
     safety measure: if you enter a definition that happens to have the
     same name as a critical system procedure, your definition will be
     visible only to the procedures you define in the
     `user-initial-environment'; the MIT/GNU Scheme system procedures,
     which are defined in `system-global-environment', will continue to
     see the original definition.


File: mit-scheme-ref.info,  Node: REPL Environment,  Next: Top-level Environments,  Prev: Environment Variables,  Up: Environments

13.3 REPL Environment
=====================

 -- procedure: nearest-repl/environment
     Returns the current REP loop environment (i.e. the current
     environment of the closest enclosing REP loop).  When Scheme first
     starts up, this is the same as `user-initial-environment'.

 -- procedure: ge environment
     Changes the current REP loop environment to ENVIRONMENT.
     ENVIRONMENT can be either an environment or a procedure object.
     If it's a procedure, the environment in which that procedure was
     closed is the new environment.


File: mit-scheme-ref.info,  Node: Top-level Environments,  Prev: REPL Environment,  Up: Environments

13.4 Top-level Environments
===========================

The operations in this section manipulate "top-level environments", as
opposed to environments created by the application of procedures.  For
historical reasons, top-level environments are referred to as
"interpreter environments".

 -- special form: the-environment
     Returns the current environment.  This form may only be evaluated
     in a top-level environment.  An error is signalled if it appears
     elsewhere.

 -- procedure: top-level-environment? object
 -- procedure: interpreter-environment? object
     Returns `#t' if OBJECT is an top-level environment; otherwise
     returns `#f'.

     `interpreter-environment?' is an alias for
     `top-level-environment?'.

 -- procedure: extend-top-level-environment environment [names [values]]
 -- procedure: make-top-level-environment [names [values]]
 -- procedure: make-root-top-level-environment [names [values]]
     Returns a newly allocated top-level environment.
     `extend-top-level-environment' creates an environment that has
     parent ENVIRONMENT, `make-top-level-environment' creates an
     environment that has parent `system-global-environment', and
     `make-root-top-level-environment' creates an environment that has
     no parent.

     The optional arguments NAMES and VALUES are used to specify
     initial bindings in the new environment.  If specified, NAMES must
     be a list of symbols, and VALUES must be a list of objects.  If
     only NAMES is specified, each name in NAMES will be bound in the
     environment, but unassigned.  If NAMES and VALUES are both
     specified, they must be the same length, and each name in NAMES
     will be bound to the corresponding value in VALUES.  If neither
     NAMES nor VALUES is specified, the environment will have no
     initial bindings.

 -- procedure: link-variables environment1 symbol1 environment2 symbol2
     Defines SYMBOL1 in ENVIRONMENT1 to have the same binding as
     SYMBOL2 in ENVIRONMENT2, and returns an unspecified value.  Prior
     to the call, SYMBOL2 must be bound in ENVIRONMENT2, but the type
     of binding is irrelevant; it may be a normal binding, an
     unassigned binding, or a keyword binding.  Signals an error if
     SYMBOL1 isn't definable in ENVIRONMENT1, or if SYMBOL2 is unbound
     in ENVIRONMENT2.

     By "the same binding", we mean that the value cell is shared
     between the two environments.  If a value is assigned to SYMBOL1 in
     ENVIRONMENT1, a subsequent reference to SYMBOL2 in ENVIRONMENT2
     will see that value, and vice versa.

 -- procedure: unbind-variable environment symbol
     If SYMBOL is bound in ENVIRONMENT or one of its ancestor
     environments, removes the binding, so that subsequent accesses to
     that symbol behave as if the binding never existed.  Returns `#t'
     if there was a binding prior to the call, and `#f' if there wasn't.


File: mit-scheme-ref.info,  Node: Input/Output,  Next: Operating-System Interface,  Prev: Environments,  Up: Top

14 Input/Output
***************

This chapter describes the procedures that are used for input and
output (I/O).  The chapter first describes "ports" and how they are
manipulated, then describes the I/O operations.  Finally, some
low-level procedures are described that permit the implementation of
custom ports and high-performance I/O.

* Menu:

* Ports::
* File Ports::
* String Ports::
* Input Procedures::
* Output Procedures::
* Format::
* Custom Output::
* Prompting::
* Port Primitives::
* Parser Buffers::
* Parser Language::
* XML Support::


File: mit-scheme-ref.info,  Node: Ports,  Next: File Ports,  Prev: Input/Output,  Up: Input/Output

14.1 Ports
==========

Scheme uses ports for I/O.  A "port", which can be treated like any
other Scheme object, serves as a source or sink for data.  A port must
be open before it can be read from or written to.  The standard I/O
port, `console-i/o-port', is opened automatically when you start
Scheme.  When you use a file for input or output, you need to
explicitly open and close a port to the file (with procedures described
in this chapter).  Additional procedures let you open ports to strings.

   Many input procedures, such as `read-char' and `read', read data
from the current input port by default, or from a port that you
specify.  The current input port is initially `console-i/o-port', but
Scheme provides procedures that let you change the current input port
to be a file or string.

   Similarly, many output procedures, such as `write-char' and
`display', write data to the current output port by default, or to a
port that you specify.  The current output port is initially
`console-i/o-port', but Scheme provides procedures that let you change
the current output port to be a file or string.

   Nearly all ports read or write Unicode characters; the exceptions are
those for which non-Unicode character coding has been specified.

   Every port is either an input port, an output port, or both.  The
following predicates distinguish all of the possible cases.

 -- procedure: port? object
     Returns `#t' if OBJECT is a port, otherwise returns `#f'.

 -- procedure: input-port? object
     Returns `#t' if OBJECT is an input port, otherwise returns `#f'.
     Any object satisfying this predicate also satisfies `port?'.

 -- procedure: output-port? object
     Returns `#t' if OBJECT is an output port, otherwise returns `#f'.
     Any object satisfying this predicate also satisfies `port?'.

 -- procedure: i/o-port? object
     Returns `#t' if OBJECT is both an input port and an output port,
     otherwise returns `#f'.  Any object satisfying this predicate also
     satisfies `port?', `input-port?', and `output-port?'.

 -- procedure: guarantee-port object
 -- procedure: guarantee-input-port object
 -- procedure: guarantee-output-port object
 -- procedure: guarantee-i/o-port object
     These procedures check the type of OBJECT, signalling an error of
     type
     `condition-type:wrong-type-argument' if it is not a port, input
     port, output port, or I/O port, respectively.  Otherwise they
     return OBJECT.  

   The next five procedures return the runtime system's "standard
ports".  All of the standard ports are dynamically bound by the REP
loop; this means that when a new REP loop is started, for example by an
error, each of these ports is dynamically bound to the I/O port of the
REP loop.  When the REP loop exits, the ports revert to their original
values.

 -- procedure: current-input-port
     Returns the current input port.  This is the default port used by
     many input procedures.  Initially, `current-input-port' returns the
     value of `console-i/o-port'.

 -- procedure: current-output-port
     Returns the current output port.  This is the default port used by
     many output procedures.  Initially, `current-output-port' returns
     the value of `console-i/o-port'.

 -- procedure: notification-output-port
     Returns an output port suitable for generating "notifications",
     that is, messages to the user that supply interesting information
     about the execution of a program.  For example, the `load'
     procedure writes messages to this port informing the user that a
     file is being loaded.  Initially, `notification-output-port'
     returns the value of `console-i/o-port'.

 -- procedure: trace-output-port
     Returns an output port suitable for generating "tracing"
     information about a program's execution.  The output generated by
     the `trace' procedure is sent to this port.  Initially,
     `trace-output-port' returns the value of `console-i/o-port'.

 -- procedure: interaction-i/o-port
     Returns an I/O port suitable for querying or prompting the user.
     The standard prompting procedures use this port by default (*note
     Prompting::).  Initially, `interaction-i/o-port' returns the value
     of `console-i/o-port'.

 -- procedure: with-input-from-port input-port thunk
 -- procedure: with-output-to-port output-port thunk
 -- procedure: with-notification-output-port output-port thunk
 -- procedure: with-trace-output-port output-port thunk
 -- procedure: with-interaction-i/o-port i/o-port thunk
     THUNK must be a procedure of no arguments.  Each of these
     procedures binds one of the standard ports to its first argument,
     calls THUNK with no arguments, restores the port to its original
     value, and returns the result that was yielded by THUNK.  This
     temporary binding is performed the same way as dynamic binding of
     a variable, including the behavior in the presence of
     continuations (*note Dynamic Binding::).

     `with-input-from-port' binds the current input port,
     `with-output-to-port' binds the current output port,
     `with-notification-output-port' binds the "notification" output
     port, `with-trace-output-port' binds the "trace" output port, and
     `with-interaction-i/o-port' binds the "interaction" I/O port.

 -- procedure: set-current-input-port! input-port
 -- procedure: set-current-output-port! output-port
 -- procedure: set-notification-output-port! output-port
 -- procedure: set-trace-output-port! output-port
 -- procedure: set-interaction-i/o-port! i/o-port
     Each of these procedures alters the binding of one of the standard
     ports and returns an unspecified value.  The binding that is
     modified corresponds to the name of the procedure.

 -- variable: console-i/o-port
     `console-i/o-port' is an I/O port that communicates with the
     "console".  Under unix, the console is the controlling terminal of
     the Scheme process.  Under Windows, the console is the window that
     is created when Scheme starts up.

     This variable is rarely used; instead programs should use one of
     the standard ports defined above.  This variable should not be
     modified.

 -- procedure: close-port port
     Closes PORT and returns an unspecified value.  If PORT is a file
     port, the file is closed.

 -- procedure: close-input-port port
     Closes PORT and returns an unspecified value.  PORT must be an
     input port or an I/O port; if it is an I/O port, then only the
     input side of the port is closed.

 -- procedure: close-output-port port
     Closes PORT and returns an unspecified value.  PORT must be an
     output port or an I/O port; if it is an I/O port, then only the
     output side of the port is closed.


File: mit-scheme-ref.info,  Node: File Ports,  Next: String Ports,  Prev: Ports,  Up: Input/Output

14.2 File Ports
===============

Before Scheme can access a file for reading or writing, it is necessary
to open a port to the file.  This section describes procedures used to
open ports to files.  Such ports are closed (like any other port) by
`close-port'.  File ports are automatically closed if and when they are
reclaimed by the garbage collector.

   Before opening a file for input or output, by whatever method, the
FILENAME argument is converted to canonical form by calling the
procedure `merge-pathnames' with FILENAME as its sole argument.  Thus,
FILENAME can be either a string or a pathname, and it is merged with
the current pathname defaults to produce the pathname that is then
opened.

   Any file can be opened in one of two modes, "normal" or "binary".
Normal mode is for accessing text files, and binary mode is for
accessing other files.  Unix does not distinguish these modes, but
Windows do: in normal mode, their file ports perform "newline
translation", mapping between the carriage-return/linefeed sequence
that terminates text lines in files, and the `#\newline' that
terminates lines in Scheme.  In binary mode, such ports do not perform
newline translation.  Unless otherwise mentioned, the procedures in
this section open files in normal mode.

 -- procedure: open-input-file filename
     Takes a filename referring to an existing file and returns an
     input port capable of delivering characters from the file.  If the
     file cannot be opened, an error of type
     `condition-type:file-operation-error' is signalled.  

 -- procedure: open-output-file filename [append?]
     Takes a filename referring to an output file to be created and
     returns an output port capable of writing characters to a new file
     by that name.  If the file cannot be opened, an error of type
     `condition-type:file-operation-error' is signalled.  

     The optional argument APPEND? is an MIT/GNU Scheme extension.  If
     APPEND? is given and not `#f', the file is opened in "append"
     mode.  In this mode, the contents of the file are not overwritten;
     instead any characters written to the file are appended to the end
     of the existing contents.  If the file does not exist, append mode
     creates the file and writes to it in the normal way.

 -- procedure: open-i/o-file filename
     Takes a filename referring to an existing file and returns an I/O
     port capable of both reading and writing the file.  If the file
     cannot be opened, an error of type
     `condition-type:file-operation-error' is signalled.  

     This procedure is often used to open special files.  For example,
     under unix this procedure can be used to open terminal device
     files, PTY device files, and named pipes.

 -- procedure: open-binary-input-file filename
 -- procedure: open-binary-output-file filename [append?]
 -- procedure: open-binary-i/o-file filename
     These procedures open files in binary mode.  In all other respects
     they are identical to `open-input-file', `open-output-file', and
     `open-i/o-file', respectively.

 -- procedure: close-all-open-files
     This procedure closes all file ports that are open at the time
     that it is called, and returns an unspecified value.

 -- procedure: call-with-input-file filename procedure
 -- procedure: call-with-output-file filename procedure
     These procedures call PROCEDURE with one argument: the port
     obtained by opening the named file for input or output,
     respectively.  If the file cannot be opened, an error of type
     `condition-type:file-operation-error' is signalled.  If PROCEDURE
     returns, then the port is closed automatically and the value
     yielded by PROCEDURE is returned.  If PROCEDURE does not return,
     then the port will not be closed automatically unless it is
     reclaimed by the garbage collector.(1)

 -- procedure: call-with-binary-input-file filename procedure
 -- procedure: call-with-binary-output-file filename procedure
     These procedures open files in binary mode.  In all other respects
     they are identical to `call-with-input-file' and
     `call-with-output-file', respectively.

 -- procedure: with-input-from-file filename thunk
 -- procedure: with-output-to-file filename thunk
     THUNK must be a procedure of no arguments.  The file is opened for
     input or output, an input or output port connected to it is made
     the default value returned by `current-input-port' or
     `current-output-port', and the THUNK is called with no arguments.
     When the THUNK returns, the port is closed and the previous
     default is restored.  `with-input-from-file' and
     `with-output-to-file' return the value yielded by THUNK.  If an
     escape procedure is used to escape from the continuation of these
     procedures, their behavior is implementation-dependent; in that
     situation MIT/GNU Scheme leaves the files open.

 -- procedure: with-input-from-binary-file filename thunk
 -- procedure: with-output-to-binary-file filename thunk
     These procedures open files in binary mode.  In all other respects
     they are identical to `with-input-from-file' and
     `with-output-to-file', respectively.

   ---------- Footnotes ----------

   (1) Because Scheme's escape procedures have unlimited extent, it is
possible to escape from the current continuation but later to escape
back in.  If implementations were permitted to close the port on any
escape from the current continuation, then it would be impossible to
write portable code using both `call-with-current-continuation' and
`call-with-input-file' or `call-with-output-file'.


File: mit-scheme-ref.info,  Node: String Ports,  Next: Input Procedures,  Prev: File Ports,  Up: Input/Output

14.3 String Ports
=================

This section describes the simplest kinds of ports: input ports that
read their input from given strings, and output ports that accumulate
their output and return it as a string.  It also describes "truncating"
output ports, which can limit the length of the resulting string to a
given value.

 -- procedure: open-input-string string [start [end]]
     Returns a new string port that delivers characters from STRING.
     The optional arguments START and END may be used to specify that
     the string port delivers characters from a substring of STRING; if
     not given, START defaults to `0' and END defaults to
     `(string-length STRING)'.

 -- procedure: with-input-from-string string thunk
     THUNK must be a procedure of no arguments.
     `with-input-from-string' creates a new input port that reads from
     STRING, makes that port the current input port, and calls THUNK.
     When THUNK returns, `with-input-from-string' restores the previous
     current input port and returns the result yielded by THUNK.

          (with-input-from-string "(a b c) (d e f)" read)  =>  (a b c)

     Note: this procedure is equivalent to:

          (with-input-from-port (open-input-string STRING) THUNK)

 -- procedure: open-output-string
 -- procedure: get-output-string
     `open-output-string' returns a new output port that accumulates in
     a buffer everything that is written to it.  The accumulated output
     can subsequently be obtained by calling `get-output-string' on the
     port.

 -- procedure: call-with-output-string procedure
     PROCEDURE is called with one argument, an output port.  The value
     yielded by PROCEDURE is ignored.  When PROCEDURE returns,
     `call-with-output-string' returns the port's accumulated output as
     a newly allocated string.  This is equivalent to:

          (define (call-with-output-string procedure)
            (let ((port (open-output-string)))
              (procedure port)
              (get-output-string port)))

 -- procedure: with-output-to-string thunk
     THUNK must be a procedure of no arguments.
     `with-output-to-string' creates a new output port that accumulates
     output, makes that port the default value returned by
     `current-output-port', and calls THUNK with no arguments.  When
     THUNK returns, `with-output-to-string' restores the previous
     default and returns the accumulated output as a newly allocated
     string.

          (with-output-to-string
            (lambda ()
              (write 'abc)))                    =>  "abc"

     Note: this procedure is equivalent to:

          (call-with-output-string
           (lambda (port)
             (with-output-to-port port THUNK)))

 -- procedure: with-output-to-truncated-string k thunk
     Similar to `with-output-to-string', except that the output is
     limited to K characters.  If THUNK attempts to write more than K
     characters, it will be aborted by invoking an escape procedure
     that returns from `with-output-to-truncated-string'.

     The value of this procedure is a pair; the car of the pair is `#t'
     if THUNK attempted to write more than K characters, and `#f'
     otherwise.  The cdr of the pair is a newly allocated string
     containing the accumulated output.

     This procedure is helpful for displaying circular lists, as shown
     in this example:

          (define inf (list 'inf))
          (with-output-to-truncated-string 40
            (lambda ()
              (write inf)))                       =>  (#f . "(inf)")
          (set-cdr! inf inf)
          (with-output-to-truncated-string 40
            (lambda ()
              (write inf)))
                  =>  (#t . "(inf inf inf inf inf inf inf inf inf inf")

 -- procedure: write-to-string object [k]
     Writes OBJECT to a string output port, and returns the resulting
     newly allocated string.  If K is supplied and not `#f', this
     procedure is equivalent to

          (with-output-to-truncated-string K
            (lambda ()
              (write OBJECT)))

     otherwise it is equivalent to

          (with-output-to-string
           (lambda ()
             (write OBJECT)))


File: mit-scheme-ref.info,  Node: Input Procedures,  Next: Output Procedures,  Prev: String Ports,  Up: Input/Output

14.4 Input Procedures
=====================

This section describes the procedures that read input.  Input procedures
can read either from the current input port or from a given port.
Remember that to read from a file, you must first open a port to the
file.

   Input ports can be divided into two types, called "interactive" and
"non-interactive".  Interactive input ports are ports that read input
from a source that is time-dependent; for example, a port that reads
input from a terminal or from another program.  Non-interactive input
ports read input from a time-independent source, such as an ordinary
file or a character string.

   All optional arguments called INPUT-PORT, if not supplied, default
to the current input port.

 -- procedure: read-char [input-port]
     Returns the next character available from INPUT-PORT, updating
     INPUT-PORT to point to the following character.  If no more
     characters are available, an end-of-file object is returned.

     In MIT/GNU Scheme, if INPUT-PORT is an interactive input port and
     no characters are immediately available, `read-char' will hang
     waiting for input, even if the port is in non-blocking mode.

 -- procedure: peek-char [input-port]
     Returns the next character available from INPUT-PORT, _without_
     updating INPUT-PORT to point to the following character.  If no
     more characters are available, an end-of-file object is
     returned.(1)

     In MIT/GNU Scheme, if INPUT-PORT is an interactive input port and
     no characters are immediately available, `peek-char' will hang
     waiting for input, even if the port is in non-blocking mode.

 -- procedure: char-ready? [input-port]
     Returns `#t' if a character is ready on INPUT-PORT and returns
     `#f' otherwise.  If `char-ready?' returns `#t' then the next
     `read-char' operation on INPUT-PORT is guaranteed not to hang.  If
     INPUT-PORT is a file port at end of file then `char-ready?' returns
     `#t'.(2)

 -- procedure: read [input-port [environment]]
     Converts external representations of Scheme objects into the
     objects themselves.  `read' returns the next object parsable from
     INPUT-PORT, updating INPUT-PORT to point to the first character
     past the end of the written representation of the object.  If an
     end of file is encountered in the input before any characters are
     found that can begin an object, `read' returns an end-of-file
     object.  The INPUT-PORT remains open, and further attempts to read
     will also return an end-of-file object.  If an end of file is
     encountered after the beginning of an object's written
     representation, but the written representation is incomplete and
     therefore not parsable, an error is signalled.

     ENVIRONMENT is used to look up the values of control variables
     such as `*parser-radix*'.  If not supplied, it defaults to the REP
     environment.

 -- procedure: eof-object? object
     Returns `#t' if OBJECT is an end-of-file object; otherwise returns
     `#f'.

 -- procedure: read-char-no-hang [input-port]
     If INPUT-PORT can deliver a character without blocking, this
     procedure acts exactly like `read-char', immediately returning that
     character.  Otherwise, `#f' is returned, unless INPUT-PORT is a
     file port at end of file, in which case an end-of-file object is
     returned.  In no case will this procedure block waiting for input.

 -- procedure: read-string char-set [input-port]
     Reads characters from INPUT-PORT until it finds a terminating
     character that is a member of CHAR-SET (*note Character Sets::) or
     encounters end of file.  The port is updated to point to the
     terminating character, or to end of file if no terminating
     character was found.  `read-string' returns the characters, up to
     but excluding the terminating character, as a newly allocated
     string.

     This procedure ignores the blocking mode of the port, blocking
     unconditionally until it sees either a delimiter or end of file.
     If end of file is encountered before any characters are read, an
     end-of-file object is returned.

     On many input ports, this operation is significantly faster than
     the following equivalent code using `peek-char' and `read-char':

          (define (read-string char-set input-port)
            (let ((char (peek-char input-port)))
              (if (eof-object? char)
                  char
                  (list->string
                   (let loop ((char char))
                     (if (or (eof-object? char)
                             (char-set-member? char-set char))
                         '()
                         (begin
                           (read-char input-port)
                           (cons char
                                 (loop (peek-char input-port))))))))))

 -- procedure: read-line [input-port]
     `read-line' reads a single line of text from INPUT-PORT, and
     returns that line as a newly allocated string.  The `#\newline'
     terminating the line, if any, is discarded and does not appear in
     the returned string.

     This procedure ignores the blocking mode of the port, blocking
     unconditionally until it has read an entire line.  If end of file
     is encountered before any characters are read, an end-of-file
     object is returned.

 -- procedure: read-string! string [input-port]
 -- procedure: read-substring! string start end [input-port]
     `read-string!' and `read-substring!' fill the specified region of
     STRING with characters read from INPUT-PORT until the region is
     full or else there are no more characters available from the port.
     For `read-string!', the region is all of STRING, and for
     `read-substring!', the region is that part of STRING specified by
     START and END.

     The returned value is the number of characters filled into the
     region.  However, there are several interesting cases to consider:

        * If `read-string!' (`read-substring!') is called when
          INPUT-PORT is at "end-of-file", then the returned value is
          `0'.  Note that "end-of-file" can mean a file port that is at
          the file's end, a string port that is at the string's end, or
          any other port that will never produce more characters.

        * If INPUT-PORT is an interactive port (e.g. a terminal), and
          one or more characters are immediately available, the region
          is filled using the available characters.  The procedure then
          returns immediately, without waiting for further characters,
          even if the number of available characters is less than the
          size of the region.  The returned value is the number of
          characters actually filled in.

        * If INPUT-PORT is an interactive port and no characters are
          immediately available, the result of the operation depends on
          the blocking mode of the port.  If the port is in
          non-blocking mode, `read-string!' (`read-substring!')
          immediately returns the value `#f'.  Otherwise, the operation
          blocks until a character is available.  As soon as at least
          one character is available, the region is filled using the
          available characters.  The procedure then returns
          immediately, without waiting for further characters, even if
          the number of available characters is less than the size of
          the region.  The returned value is the number of characters
          actually filled in.

     The importance of `read-string!' and `read-substring!' are that
     they are both flexible and extremely fast, especially for large
     amounts of data.

   The following variables may be bound or assigned to change the
behavior of the `read' procedure.  They are looked up in the environment
that is passed to `read', and so may have different values in different
environments.  It is recommended that the global bindings of these
variables be left unchanged; make local changes by shadowing the global
bindings in nested environments.

 -- variable: *parser-radix*
     This variable defines the radix used by the reader when it parses
     numbers.  This is similar to passing a radix argument to
     `string->number'.  The value of this variable must be one of `2',
     `8', `10', or `16'; any other value is ignored, and the reader
     uses radix `10'.

     Note that much of the number syntax is invalid for radixes other
     than `10'.  The reader detects cases where such invalid syntax is
     used and signals an error.  However, problems can still occur when
     `*parser-radix*' is set to `16', because syntax that normally
     denotes symbols can now denote numbers (e.g. `abc').  Because of
     this, it is usually undesirable to set this variable to anything
     other than the default.

     The default value of this variable is `10'.

 -- variable: *parser-canonicalize-symbols?*
     This variable controls how the parser handles case-sensitivity of
     symbols.  If it is bound to its default value of `#t', symbols read
     by the parser are converted to lower case before being interned.
     Otherwise, symbols are interned without case conversion.

     In general, it is a bad idea to use this feature, as it doesn't
     really make Scheme case-sensitive, and therefore can break
     features of the Scheme runtime that depend on case-insensitive
     symbols.

   ---------- Footnotes ----------

   (1) The value returned by a call to `peek-char' is the same as the
value that would have been returned by a call to `read-char' on the
same port.  The only difference is that the very next call to
`read-char' or `peek-char' on that INPUT-PORT will return the value
returned by the preceding call to `peek-char'.  In particular, a call
to `peek-char' on an interactive port will hang waiting for input
whenever a call to `read-char' would have hung.

   (2) `char-ready?' exists to make it possible for a program to accept
characters from interactive ports without getting stuck waiting for
input.  Any input editors associated with such ports must make sure
that characters whose existence has been asserted by `char-ready?'
cannot be rubbed out.  If `char-ready?' were to return `#f' at end of
file, a port at end of file would be indistinguishable from an
interactive port that has no ready characters.


File: mit-scheme-ref.info,  Node: Output Procedures,  Next: Format,  Prev: Input Procedures,  Up: Input/Output

14.5 Output Procedures
======================

Output ports may or may not support "buffering" of output, in which
output characters are collected together in a buffer and then sent to
the output device all at once.  (Most of the output ports implemented by
the runtime system support buffering.)  Sending all of the characters in
the buffer to the output device is called "flushing" the buffer.  In
general, output procedures do not flush the buffer of an output port
unless the buffer is full.

   However, the standard output procedures described in this section
perform what is called "discretionary" flushing of the buffer.
Discretionary output flushing works as follows.  After a procedure
performs its output (writing characters to the output buffer), it checks
to see if the port implements an operation called
`discretionary-flush-output'.  If so, then that operation is invoked to
flush the buffer.  At present, only the console port defines
`discretionary-flush-output'; this is used to guarantee that output to
the console appears immediately after it is written, without requiring
calls to `flush-output'.

   All optional arguments called OUTPUT-PORT, if not supplied, default
to the current output port.

 -- procedure: write-char char [output-port]
     Writes CHAR (the character itself, not a written representation of
     the character) to OUTPUT-PORT, performs discretionary output
     flushing, and returns an unspecified value.

 -- procedure: write-string string [output-port]
     Writes STRING to OUTPUT-PORT, performs discretionary output
     flushing, and returns an unspecified value.  This is equivalent to
     writing the contents of STRING, one character at a time using
     `write-char', except that it is usually much faster.

 -- procedure: write-substring string start end [output-port]
     Writes the substring defined by STRING, START, and END to
     OUTPUT-PORT, performs discretionary output flushing, and returns
     an unspecified value.  This is equivalent to writing the contents
     of the substring, one character at a time using `write-char',
     except that it is usually much faster.

 -- procedure: write object [output-port]
     Writes a written representation of OBJECT to OUTPUT-PORT, and
     returns an unspecified value.  If OBJECT has a standard external
     representation, then the written representation generated by
     `write' shall be parsable by `read' into an equivalent object.
     Thus strings that appear in the written representation are
     enclosed in doublequotes, and within those strings backslash and
     doublequote are escaped by backslashes.  `write' performs
     discretionary output flushing and returns an unspecified value.

 -- procedure: display object [output-port]
     Writes a representation of OBJECT to OUTPUT-PORT.  Strings appear
     in the written representation as if written by `write-string'
     instead of by `write'.  Character objects appear in the
     representation as if written by `write-char' instead of by
     `write'.  `display' performs discretionary output flushing and
     returns an unspecified value.(1)

 -- procedure: newline [output-port]
     Writes an end-of-line to OUTPUT-PORT, performs discretionary
     output flushing, and returns an unspecified value.  Equivalent to
     `(write-char #\newline OUTPUT-PORT)'.

 -- procedure: fresh-line [output-port]
     Most output ports are able to tell whether or not they are at the
     beginning of a line of output.  If OUTPUT-PORT is such a port,
     this procedure writes an end-of-line to the port only if the port
     is not already at the beginning of a line.  If OUTPUT-PORT is not
     such a port, this procedure is identical to `newline'.  In either
     case, `fresh-line' performs discretionary output flushing and
     returns an unspecified value.

 -- procedure: write-line object [output-port]
     Like `write', except that it writes an end-of-line to OUTPUT-PORT
     after writing OBJECT's representation.  This procedure performs
     discretionary output flushing and returns an unspecified value.

 -- procedure: flush-output [output-port]
     If OUTPUT-PORT is buffered, this causes the contents of its buffer
     to be written to the output device.  Otherwise it has no effect.
     Returns an unspecified value.

 -- procedure: beep [output-port]
     Performs a "beep" operation on OUTPUT-PORT, performs discretionary
     output flushing, and returns an unspecified value.  On the console
     port, this usually causes the console bell to beep, but more
     sophisticated interactive ports may take other actions, such as
     flashing the screen.  On most output ports, e.g. file and string
     output ports, this does nothing.

 -- procedure: clear [output-port]
     "Clears the screen" of OUTPUT-PORT, performs discretionary output
     flushing, and returns an unspecified value.  On a terminal or
     window, this has a well-defined effect.  On other output ports,
     e.g.  file and string output ports, this does nothing.

 -- procedure: pp object [output-port [as-code?]]
     `pp' prints OBJECT in a visually appealing and structurally
     revealing manner on OUTPUT-PORT.  If object is a procedure, `pp'
     attempts to print the source text.  If the optional argument
     AS-CODE? is true, `pp' prints lists as Scheme code, providing
     appropriate indentation; by default this argument is false.  `pp'
     performs discretionary output flushing and returns an unspecified
     value.

   The following variables may be dynamically bound to change the
behavior of the `write' and `display' procedures.

 -- variable: *unparser-radix*
     This variable specifies the default radix used to print numbers.
     Its value must be one of the exact integers `2', `8', `10', or
     `16'; the default is `10'.  If `*unparser-radix*' is not `10',
     numbers are prefixed to indicate their radix.

 -- variable: *unparser-list-breadth-limit*
     This variable specifies a limit on the length of the printed
     representation of a list or vector; for example, if the limit is
     `4', only the first four elements of any list are printed, followed
     by ellipses to indicate any additional elements.  The value of this
     variable must be an exact non-negative integer, or `#f' meaning no
     limit; the default is `#f'.

          (fluid-let ((*unparser-list-breadth-limit* 4))
            (write-to-string '(a b c d)))
                                          => "(a b c d)"
          (fluid-let ((*unparser-list-breadth-limit* 4))
            (write-to-string '(a b c d e)))
                                          => "(a b c d ...)"

 -- variable: *unparser-list-depth-limit*
     This variable specifies a limit on the nesting of lists and
     vectors in the printed representation.  If lists (or vectors) are
     more deeply nested than the limit, the part of the representation
     that exceeds the limit is replaced by ellipses.  The value of this
     variable must be an exact non-negative integer, or `#f' meaning no
     limit; the default is `#f'.

          (fluid-let ((*unparser-list-depth-limit* 4))
            (write-to-string '((((a))) b c d)))
                                          => "((((a))) b c d)"
          (fluid-let ((*unparser-list-depth-limit* 4))
            (write-to-string '(((((a)))) b c d)))
                                          => "((((...))) b c d)"

 -- variable: *unparser-string-length-limit*
     This variable specifies a limit on the length of the printed
     representation of strings.  If a string's length exceeds this
     limit, the part of the printed representation for the characters
     exceeding the limit is replaced by ellipses.  The value of this
     variable must be an exact non-negative integer, or `#f' meaning no
     limit; the default is `#f'.

          (fluid-let ((*unparser-string-length-limit* 4))
            (write-to-string "abcd"))
                                          => "\"abcd\""
          (fluid-let ((*unparser-string-length-limit* 4))
            (write-to-string "abcde"))
                                          => "\"abcd...\""

 -- variable: *unparse-with-maximum-readability?*
     This variable, which takes a boolean value, tells the printer to
     use a special printed representation for objects that normally
     print in a form that cannot be recognized by `read'.  These
     objects are printed using the representation `#@N', where N is the
     result of calling `hash' on the object to be printed.  The reader
     recognizes this syntax, calling `unhash' on N to get back the
     original object.  Note that this printed representation can only be
     recognized by the Scheme program in which it was generated, because
     these hash numbers are different for each invocation of Scheme.

   ---------- Footnotes ----------

   (1) `write' is intended for producing machine-readable output and
`display' is for producing human-readable output.


File: mit-scheme-ref.info,  Node: Format,  Next: Custom Output,  Prev: Output Procedures,  Up: Input/Output

14.6 Format
===========

The procedure `format' is very useful for producing nicely formatted
text, producing good-looking messages, and so on.  MIT/GNU Scheme's
implementation of `format' is similar to that of Common Lisp, except
that Common Lisp defines many more directives.(1)

   `format' is a run-time-loadable option.  To use it, execute

     (load-option 'format)
   
once before calling it.

 -- procedure: format destination control-string argument ...
     Writes the characters of CONTROL-STRING to DESTINATION, except
     that a tilde (`~') introduces a "format directive".  The character
     after the tilde, possibly preceded by prefix parameters and
     modifiers, specifies what kind of formatting is desired.  Most
     directives use one or more ARGUMENTs to create their output; the
     typical directive puts the next ARGUMENT into the output,
     formatted in some special way.  It is an error if no argument
     remains for a directive requiring an argument, but it is not an
     error if one or more arguments remain unprocessed by a directive.

     The output is sent to DESTINATION.  If DESTINATION is `#f', a
     string is created that contains the output; this string is
     returned as the value of the call to `format'.  In all other cases
     `format' returns an unspecified value.  If DESTINATION is `#t',
     the output is sent to the current output port.  Otherwise,
     DESTINATION must be an output port, and the output is sent there.

     This procedure performs discretionary output flushing (*note
     Output Procedures::).

     A `format' directive consists of a tilde (`~'), optional prefix
     parameters separated by commas, optional colon (`:') and at-sign
     (`@') modifiers, and a single character indicating what kind of
     directive this is.  The alphabetic case of the directive character
     is ignored.  The prefix parameters are generally integers, notated
     as optionally signed decimal numbers.  If both the colon and
     at-sign modifiers are given, they may appear in either order.

     In place of a prefix parameter to a directive, you can put the
     letter `V' (or `v'), which takes an ARGUMENT for use as a
     parameter to the directive.  Normally this should be an exact
     integer.  This feature allows variable-width fields and the like.
     You can also use the character `#' in place of a parameter; it
     represents the number of arguments remaining to be processed.

     It is an error to give a format directive more parameters than it
     is described here as accepting.  It is also an error to give colon
     or at-sign modifiers to a directive in a combination not
     specifically described here as being meaningful.

    `~A'
          The next ARGUMENT, which may be any object, is printed as if
          by `display'.  `~MINCOLA' inserts spaces on the right, if
          necessary, to make the width at least MINCOL columns.  The
          `@' modifier causes the spaces to be inserted on the left
          rather than the right.

    `~S'
          The next ARGUMENT, which may be any object, is printed as if
          by `write'.  `~MINCOLS' inserts spaces on the right, if
          necessary, to make the width at least MINCOL columns.  The
          `@' modifier causes the spaces to be inserted on the left
          rather than the right.

    `~%'
          This outputs a `#\newline' character.  `~N%' outputs N
          newlines.  No ARGUMENT is used.  Simply putting a newline in
          CONTROL-STRING would work, but `~%' is often used because it
          makes the control string look nicer in the middle of a
          program.

    `~~'
          This outputs a tilde.  `~N~' outputs N tildes.

    `~NEWLINE'
          Tilde immediately followed by a newline ignores the newline
          and any following non-newline whitespace characters.  With an
          `@', the newline is left in place, but any following
          whitespace is ignored.  This directive is typically used when
          CONTROL-STRING is too long to fit nicely into one line of the
          program:

               (define (type-clash-error procedure arg spec actual)
                 (format
                  #t
                  "~%Procedure ~S~%requires its %A argument ~
                   to be of type ~S,~%but it was called with ~
                   an argument of type ~S.~%"
                  procedure arg spec actual))

               (type-clash-error 'vector-ref
                                 "first"
                                 'integer
                                 'vector)

               prints

               Procedure vector-ref
               requires its first argument to be of type integer,
               but it was called with an argument of type vector.

          Note that in this example newlines appear in the output only
          as specified by the `~%' directives; the actual newline
          characters in the control string are suppressed because each
          is preceded by a tilde.

   ---------- Footnotes ----------

   (1) This description of `format' is adapted from `Common Lisp, The
Language', second edition, section 22.3.3.


File: mit-scheme-ref.info,  Node: Custom Output,  Next: Prompting,  Prev: Format,  Up: Input/Output

14.7 Custom Output
==================

MIT/GNU Scheme provides hooks for specifying that certain kinds of
objects have special written representations.  There are no
restrictions on the written representations, but only a few kinds of
objects may have custom representation specified for them,
specifically: records (*note Records::), vectors that have special tags
in their zero-th elements (*note Vectors::), and pairs that have
special tags in their car fields (*note Lists::).  There is a different
procedure for specifying the written representation of each of these
types.

 -- procedure: set-record-type-unparser-method! record-type
          unparser-method
     Changes the unparser method of the type represented by RECORD-TYPE
     to be UNPARSER-METHOD, and returns an unspecified value.
     Subsequently, when the unparser encounters a record of this type,
     it will invoke UNPARSER-METHOD to generate the written
     representation.

 -- procedure: unparser/set-tagged-vector-method! tag unparser-method
     Changes the unparser method of the vector type represented by TAG
     to be UNPARSER-METHOD, and returns an unspecified value.
     Subsequently, when the unparser encounters a vector with TAG as
     its zero-th element, it will invoke UNPARSER-METHOD to generate
     the written representation.

 -- procedure: unparser/set-tagged-pair-method! tag unparser-method
     Changes the unparser method of the pair type represented by TAG to
     be UNPARSER-METHOD, and returns an unspecified value.
     Subsequently, when the unparser encounters a pair with TAG in its
     car field, it will invoke UNPARSER-METHOD to generate the written
     representation.

   An "unparser method" is a procedure that is invoked with two
arguments: an unparser state and an object.  An unparser method
generates a written representation for the object, writing it to the
output port specified by the unparser state.  The value yielded by an
unparser method is ignored.  Note that an unparser state is not an
output port, rather it is an object that contains an output port as one
of its components.  Application programs generally do not construct or
examine unparser state objects, but just pass them along.

   There are two ways to create an unparser method (which is then
registered by one of the above procedures).  The first, and easiest, is
to use `standard-unparser-method'.  The second is to define your own
method using the procedure `with-current-unparser-state'.  We encourage
the use of the first method, as it results in a more uniform appearance
for objects.  Many predefined datatypes, for example procedures and
environments, already have this appearance.

 -- procedure: standard-unparser-method name procedure
     Returns a standard unparser method.  NAME may be any object, and
     is used as the name of the type with which the unparser method is
     associated; NAME is usually a symbol.  PROCEDURE must be `#f' or a
     procedure of two arguments.

     If PROCEDURE is `#f', the returned method generates an external
     representation of this form:

          #[NAME HASH]

     Here NAME is the external representation of the argument NAME, as
     generated by `write',(1) and HASH is the external representation
     of an exact non-negative integer unique to the object being
     printed (specifically, it is the result of calling `hash' on the
     object).  Subsequently, the expression

          #@HASH

     is notation for an expression evaluating to the object.

     If PROCEDURE is supplied, the returned method generates a slightly
     different external representation:

          #[NAME HASH OUTPUT]

     Here NAME and HASH are as above, and OUTPUT is the output
     generated by PROCEDURE.  The representation is constructed in
     three stages:

       1. The first part of the format (up to OUTPUT) is written to the
          output port specified by the unparser state.  This is `"#["',
          NAME, `" "', and HASH.

       2. PROCEDURE is invoked on two arguments: the object and an
          output port.

       3. The closing bracket is written to the output port.

   The following procedure is useful for writing more general kinds of
unparser methods.

 -- procedure: with-current-unparser-state unparser-state procedure
     This procedure calls PROCEDURE with one argument, the output port
     from UNPARSER-STATE.  Additionally, it arranges for the remaining
     components of UNPARSER-STATE to be given to the printer when they
     are needed.  The PROCEDURE generates some output by writing to the
     output port using the usual output operations, and the value
     yielded by PROCEDURE is returned from
     `with-current-unparser-state'.

     The port passed to PROCEDURE should only be used within the
     dynamic extent of PROCEDURE.

   ---------- Footnotes ----------

   (1) Except that if the argument NAME is a string, its external
representation is generated by `write-string'.


File: mit-scheme-ref.info,  Node: Prompting,  Next: Port Primitives,  Prev: Custom Output,  Up: Input/Output

14.8 Prompting
==============

This section describes procedures that prompt the user for input.  Why
should the programmer use these procedures when it is possible to do
prompting using ordinary input and output procedures?  One reason is
that the prompting procedures are more succinct.  However, a second and
better reason is that the prompting procedures can be separately
customized for each user interface, providing more natural interaction.
The interfaces for Edwin and for GNU Emacs have already been customized
in this fashion; because Edwin and Emacs are very similar editors, their
customizations provide very similar behavior.

   Each of these procedure accepts an optional argument called PORT,
which if given must be an I/O port.  If not given, this port defaults
to the value of `(interaction-i/o-port)'; this is initially the console
I/O port.

 -- procedure: prompt-for-command-expression prompt [port [environment]]
     Prompts the user for an expression that is to be executed as a
     command.  This is the procedure called by the REP loop to read the
     user's expressions.

     If PROMPT is a string, it is used verbatim as the prompt string.
     Otherwise, it must be a pair whose car is the symbol `standard' and
     whose cdr is a string; in this case the prompt string is formed by
     prepending to the string the current REP loop "level number" and a
     space.  Also, a space is appended to the string, unless it already
     ends in a space or is an empty string.

     If ENVIRONMENT is given, it is passed as the second argument to
     `read'.

     The default behavior of this procedure is to print a fresh line, a
     newline, and the prompt string; flush the output buffer; then read
     an object and return it.

     Under Edwin and Emacs, before the object is read, the interaction
     buffer is put into a mode that allows expressions to be edited and
     submitted for input using specific editor commands.  The first
     expression that is submitted is returned as the value of this
     procedure.

 -- procedure: prompt-for-command-char prompt [port]
     Prompts the user for a single character that is to be executed as a
     command; the returned character is guaranteed to satisfy
     `char-graphic?'.  If at all possible, the character is read from
     the user interface using a mode that reads the character as a
     single keystroke; in other words, it should not be necessary for
     the user to follow the character with a carriage return or
     something similar.

     This is the procedure called by `debug' and `where' to read the
     user's commands.

     If PROMPT is a string, it is used verbatim as the prompt string.
     Otherwise, it must be a pair whose car is `standard' and whose cdr
     is a string; in this case the prompt string is formed by
     prepending to the string the current REP loop "level number" and a
     space.  Also, a space is appended to the string, unless it already
     ends in a space or is an empty string.

     The default behavior of this procedure is to print a fresh line, a
     newline, and the prompt string; flush the output buffer; read a
     character in raw mode, echo that character, and return it.

     Under Edwin and Emacs, instead of reading a character, the
     interaction buffer is put into a mode in which graphic characters
     submit themselves as input.  After this mode change, the first
     such character submitted is returned as the value of this
     procedure.

 -- procedure: prompt-for-expression prompt [port [environment]]
     Prompts the user for an expression.

     The prompt string is formed by appending a colon and a space to
     PROMPT, unless PROMPT already ends in a space or is the null
     string.

     If ENVIRONMENT is given, it is passed as the second argument to
     `read'.

     The default behavior of this procedure is to print a fresh line, a
     newline, and the prompt string; flush the output buffer; then read
     an object and return it.

     Under Edwin and Emacs, the expression is read in the minibuffer.

 -- procedure: prompt-for-evaluated-expression prompt [environment
          [port]]
     Prompts the user for an evaluated expression.  Calls
     `prompt-for-expression' to read an expression, then evaluates the
     expression using ENVIRONMENT; if ENVIRONMENT is not given, the REP
     loop environment is used.

 -- procedure: prompt-for-confirmation prompt [port]
     Prompts the user for confirmation.  The result yielded by this
     procedure is a boolean.

     The prompt string is formed by appending the string `" (y or n)? "'
     to PROMPT, unless PROMPT already ends in a space or is the null
     string.

     The default behavior of this procedure is to print a fresh line, a
     newline, and the prompt string; flush the output buffer; then read
     a character in raw mode.  If the character is `#\y', `#\Y', or
     `#\space', the procedure returns `#t'; If the character is `#\n',
     `#\N', or `#\rubout', the procedure returns `#f'.  Otherwise the
     prompt is repeated.

     Under Edwin or Emacs, the confirmation is read in the minibuffer.


File: mit-scheme-ref.info,  Node: Port Primitives,  Next: Parser Buffers,  Prev: Prompting,  Up: Input/Output

14.9 Port Primitives
====================

This section describes the low-level operations that can be used to
build and manipulate I/O ports.

   The purpose of these operations is twofold: to allow programmers to
construct new kinds of I/O ports, and to provide faster I/O operations
than those supplied by the standard high level procedures.  The latter
is useful because the standard I/O operations provide defaulting and
error checking, and sometimes other features, which are often
unnecessary.  This interface provides the means to bypass such
features, thus improving performance.

   The abstract model of an I/O port, as implemented here, is a
combination of a set of named operations and a state.  The state is an
arbitrary object, the meaning of which is determined by the operations.
The operations are defined by a mapping from names to procedures.

   The set of named operations is represented by an object called a
"port type".  A port type is constructed from a set of named
operations, and is subsequently used to construct a port.  The port type
completely specifies the behavior of the port.  Port types also support
a simple form of inheritance, allowing you to create new ports that are
similar to existing ports.

   The port operations are divided into two classes:

Standard operations
     There is a specific set of standard operations for input ports,
     and a different set for output ports.  Applications can assume
     that the standard input operations are implemented for all input
     ports, and likewise the standard output operations are implemented
     for all output ports.  

Custom operations
     Some ports support additional operations.  For example, ports that
     implement output to terminals (or windows) may define an operation
     named `y-size' that returns the height of the terminal in
     characters.  Because only some ports will implement these
     operations, programs that use custom operations must test each
     port for their existence, and be prepared to deal with ports that
     do not implement them.  

* Menu:

* Port Types::
* Constructors and Accessors for Ports::
* Input Port Operations::
* Output Port Operations::
* Blocking Mode::
* Terminal Mode::


File: mit-scheme-ref.info,  Node: Port Types,  Next: Constructors and Accessors for Ports,  Prev: Port Primitives,  Up: Port Primitives

14.9.1 Port Types
-----------------

The procedures in this section provide means for constructing port types
with standard and custom operations, and accessing their operations.

 -- procedure: make-port-type operations port-type
     Creates and returns a new port type.  OPERATIONS must be a list;
     each element is a list of two elements, the name of the operation
     (a symbol) and the procedure that implements it.  PORT-TYPE is
     either `#f' or a port type; if it is a port type, any operations
     implemented by PORT-TYPE but not specified in OPERATIONS will be
     implemented by the resulting port type.

     OPERATIONS need not contain definitions for all of the standard
     operations; the procedure will provide defaults for any standard
     operations that are not defined.  At a minimum, the following
     operations must be defined: for input ports, `read-char' and
     `peek-char'; for output ports, either `write-char' or
     `write-substring'.  I/O ports must supply the minimum operations
     for both input and output.

     If an operation in OPERATIONS is defined to be `#f', then the
     corresponding operation in PORT-TYPE is _not_ inherited.

     If `read-char' is defined in OPERATIONS, then any standard input
     operations defined in PORT-TYPE are ignored.  Likewise, if
     `write-char' or `write-substring' is defined in OPERATIONS, then
     any standard output operations defined in PORT-TYPE are ignored.
     This feature allows overriding the standard operations without
     having to enumerate them.

 -- procedure: port-type? object
 -- procedure: input-port-type? object
 -- procedure: output-port-type? object
 -- procedure: i/o-port-type? object
     These predicates return `#t' if OBJECT is a port type, input-port
     type, output-port type, or I/O-port type, respectively.
     Otherwise, they return `#f'.

 -- procedure: port-type/operations port-type
     Returns a newly allocated list containing all of the operations
     implemented by PORT-TYPE.  Each element of the list is a list of
     two elements -- the name and its associated operation.

 -- procedure: port-type/operation-names port-type
     Returns a newly allocated list whose elements are the names of the
     operations implemented by PORT-TYPE.

 -- procedure: port-type/operation port-type symbol
     Returns the operation named SYMBOL in PORT-TYPE.  If PORT-TYPE has
     no such operation, returns `#f'.


File: mit-scheme-ref.info,  Node: Constructors and Accessors for Ports,  Next: Input Port Operations,  Prev: Port Types,  Up: Port Primitives

14.9.2 Constructors and Accessors for Ports
-------------------------------------------

The procedures in this section provide means for constructing ports,
accessing the type of a port, and manipulating the state of a port.

 -- procedure: make-port port-type state
     Returns a new port with type PORT-TYPE and the given STATE.  The
     port will be an input, output, or I/O port according to PORT-TYPE.

 -- procedure: port/type port
     Returns the port type of PORT.

 -- procedure: port/state port
     Returns the state component of PORT.

 -- procedure: set-port/state! port object
     Changes the state component of PORT to be OBJECT.  Returns an
     unspecified value.

 -- procedure: port/operation port symbol
     Equivalent to

          (port-type/operation (port/type PORT) SYMBOL)

 -- procedure: port/operation-names port
     Equivalent to

          (port-type/operation-names (port/type PORT))

 -- procedure: make-eof-object input-port
     Returns an object that satisfies the predicate `eof-object?'.  This
     is sometimes useful when building input ports.


File: mit-scheme-ref.info,  Node: Input Port Operations,  Next: Output Port Operations,  Prev: Constructors and Accessors for Ports,  Up: Port Primitives

14.9.3 Input Port Operations
----------------------------

This section describes the standard operations on input ports.
Following that, some useful custom operations are described.

 -- operation on input port: read-char input-port
     Removes the next character available from INPUT-PORT and returns
     it.  If INPUT-PORT has no more characters and will never have any
     (e.g. at the end of an input file), this operation returns an
     end-of-file object.  If INPUT-PORT has no more characters but will
     eventually have some more (e.g. a terminal where nothing has been
     typed recently), and it is in non-blocking mode, `#f' is returned;
     otherwise the operation hangs until input is available.

 -- operation on input port: peek-char input-port
     Reads the next character available from INPUT-PORT and returns it.
     The character is _not_ removed from INPUT-PORT, and a subsequent
     attempt to read from the port will get that character again.  In
     other respects this operation behaves like `read-char'.

 -- operation on input port: char-ready? input-port k
     `char-ready?' returns `#t' if at least one character is available
     to be read from INPUT-PORT.  If no characters are available, the
     operation waits up to K milliseconds before returning `#f',
     returning immediately if any characters become available while it
     is waiting.

 -- operation on input port: read-string input-port char-set
 -- operation on input port: discard-chars input-port char-set
     These operations are like `read-char', except that they read or
     discard multiple characters at once.  All characters up to, but
     excluding, the first character in CHAR-SET (or end of file) are
     read from INPUT-PORT.  `read-string' returns these characters as a
     newly allocated string, while `discard-chars' discards them and
     returns an unspecified value.  These operations hang until
     sufficient input is available, even if INPUT-PORT is in
     non-blocking mode.  If end of file is encountered before any input
     characters, `read-string' returns an end-of-file object.

 -- operation on input port: read-substring input-port string start end
     Reads characters from INPUT-PORT into the substring defined by
     STRING, START, and END until either the substring has been filled
     or there are no more characters available.  Returns the number of
     characters written to the substring.

     If INPUT-PORT is an interactive port, and at least one character
     is immediately available, the available characters are written to
     the substring and this operation returns immediately.  If no
     characters are available, and INPUT-PORT is in blocking mode, the
     operation blocks until at least one character is available.
     Otherwise, the operation returns `#f' immediately.

     This is an extremely fast way to read characters from a port.

 -- procedure: input-port/read-char input-port
 -- procedure: input-port/peek-char input-port
 -- procedure: input-port/char-ready? input-port k
 -- procedure: input-port/read-string input-port char-set
 -- procedure: input-port/discard-chars input-port char-set
 -- procedure: input-port/read-substring input-port string start end
     Each of these procedures invokes the respective operation on
     INPUT-PORT.  For example, the following are equivalent:

          (input-port/read-char INPUT-PORT)
          ((port/operation INPUT-PORT 'read-char) INPUT-PORT)

   The following custom operations are implemented for input ports to
files, and will also work with some other kinds of input ports:

 -- operation on input port: eof? input-port
     Returns `#t' if INPUT-PORT is known to be at end of file,
     otherwise it returns `#f'.

 -- operation on input port: chars-remaining input-port
     Returns an estimate of the number of characters remaining to be
     read from INPUT-PORT.  This is useful only when INPUT-PORT is a
     file port in binary mode; in other cases, it returns `#f'.

 -- operation on input port: buffered-input-chars input-port
     Returns the number of unread characters that are stored in
     INPUT-PORT's buffer.  This will always be less than or equal to
     the buffer's size.

 -- operation on input port: input-buffer-size input-port
     Returns the maximum number of characters that INPUT-PORT's buffer
     can hold.

 -- operation on input port: set-input-buffer-size input-port size
     Resizes INPUT-PORT's buffer so that it can hold at most SIZE
     characters.  Characters in the buffer are discarded.  SIZE must be
     an exact non-negative integer.


File: mit-scheme-ref.info,  Node: Output Port Operations,  Next: Blocking Mode,  Prev: Input Port Operations,  Up: Port Primitives

14.9.4 Output Port Operations
-----------------------------

This section describes the standard operations on output ports.
Following that, some useful custom operations are described.

 -- operation on output port: write-char output-port char
     Writes CHAR to OUTPUT-PORT and returns an unspecified value.

 -- operation on output port: write-substring output-port string start
          end
     Writes the substring specified by STRING, START, and END to
     OUTPUT-PORT and returns an unspecified value.  Equivalent to
     writing the characters of the substring, one by one, to
     OUTPUT-PORT, but is implemented very efficiently.

 -- operation on output port: fresh-line output-port
     Most output ports are able to tell whether or not they are at the
     beginning of a line of output.  If OUTPUT-PORT is such a port,
     end-of-line is written to the port only if the port is not already
     at the beginning of a line.  If OUTPUT-PORT is not such a port, an
     end-of-line is unconditionally written to the port.  Returns an
     unspecified value.

 -- operation on output port: flush-output output-port
     If OUTPUT-PORT is buffered, this causes its buffer to be written
     out.  Otherwise it has no effect.  Returns an unspecified value.

 -- operation on output port: discretionary-flush-output output-port
     Normally, this operation does nothing.  However, ports that support
     discretionary output flushing implement this operation identically
     to `flush-output'.

 -- procedure: output-port/write-char output-port char
 -- procedure: output-port/write-substring output-port string start end
 -- procedure: output-port/fresh-line output-port
 -- procedure: output-port/flush-output output-port
 -- procedure: output-port/discretionary-flush-output output-port
     Each of these procedures invokes the respective operation on
     OUTPUT-PORT.  For example, the following are equivalent:

          (output-port/write-char OUTPUT-PORT CHAR)
          ((port/operation OUTPUT-PORT 'write-char)
           OUTPUT-PORT CHAR)

 -- procedure: output-port/write-string output-port string
     Writes STRING to OUTPUT-PORT.  Equivalent to

          (output-port/write-substring OUTPUT-PORT
                                       STRING
                                       0
                                       (string-length STRING))

   The following custom operations are generally useful.

 -- operation on output port: buffered-output-chars output-port
     Returns the number of unwritten characters that are stored in
     OUTPUT-PORT's buffer.  This will always be less than or equal to
     the buffer's size.

 -- operation on output port: output-buffer-size output-port
     Returns the maximum number of characters that OUTPUT-PORT's buffer
     can hold.

 -- operation on output port: set-output-buffer-size output-port size
     Resizes OUTPUT-PORT's buffer so that it can hold at most SIZE
     characters.  Characters in the buffer are discarded.  SIZE must be
     an exact non-negative integer.

 -- operation on output port: x-size output-port
     Returns an exact positive integer that is the width of OUTPUT-PORT
     in characters.  If OUTPUT-PORT has no natural width, e.g. if it is
     a file port, `#f' is returned.

 -- operation on output port: y-size output-port
     Returns an exact positive integer that is the height of
     OUTPUT-PORT in characters.  If OUTPUT-PORT has no natural height,
     e.g. if it is a file port, `#f' is returned.

 -- procedure: output-port/x-size output-port
     This procedure invokes the custom operation whose name is the
     symbol `x-size', if it exists.  If the `x-size' operation is both
     defined and returns a value other than `#f', that value is returned
     as the result of this procedure.  Otherwise, `output-port/x-size'
     returns a default value (currently `80').

     `output-port/x-size' is useful for programs that tailor their
     output to the width of the display (a fairly common practice).  If
     the output device is not a display, such programs normally want
     some reasonable default width to work with, and this procedure
     provides exactly that.

 -- procedure: output-port/y-size output-port
     This procedure invokes the custom operation whose name is the
     symbol `y-size', if it exists.  If the `y-size' operation is
     defined, the value it returns is returned as the result of this
     procedure; otherwise, `#f' is returned.


File: mit-scheme-ref.info,  Node: Blocking Mode,  Next: Terminal Mode,  Prev: Output Port Operations,  Up: Port Primitives

14.9.5 Blocking Mode
--------------------

An interactive port is always in one of two modes: "blocking" or
"non-blocking".  This mode is independent of the terminal mode: each
can be changed independent of the other.  Furthermore, if it is an
interactive I/O port, there are separate blocking modes for input and
for output.

   If an input port is in blocking mode, attempting to read from it
when no input is available will cause Scheme to "block", i.e. suspend
itself, until input is available.  If an input port is in non-blocking
mode, attempting to read from it when no input is available will cause
the reading procedure to return immediately, indicating the lack of
input in some way (exactly how this situation is indicated is separately
specified for each procedure or operation).

   An output port in blocking mode will block if the output device is
not ready to accept output.  In non-blocking mode it will return
immediately after performing as much output as the device will allow
(again, each procedure or operation reports this situation in its own
way).

   Interactive ports are initially in blocking mode; this can be
changed at any time with the procedures defined in this section.

   These procedures represent blocking mode by the symbol `blocking',
and non-blocking mode by the symbol `nonblocking'.  An argument called
MODE must be one of these symbols.  A PORT argument to any of these
procedures may be any port, even if that port does not support blocking
mode; in that case, the port is not modified in any way.

 -- procedure: port/input-blocking-mode port
     Returns the input blocking mode of PORT.

 -- procedure: port/set-input-blocking-mode port mode
     Changes the input blocking mode of PORT to be MODE.  Returns an
     unspecified value.

 -- procedure: port/with-input-blocking-mode port mode thunk
     THUNK must be a procedure of no arguments.
     `port/with-input-blocking-mode' binds the input blocking mode of
     PORT to be MODE, executes THUNK, restores the input blocking mode
     of PORT to what it was when `port/with-input-blocking-mode' was
     called, and returns the value that was yielded by THUNK.  This
     binding is performed by `dynamic-wind', which guarantees that the
     input blocking mode is restored if THUNK escapes from its
     continuation.

 -- procedure: port/output-blocking-mode port
     Returns the output blocking mode of PORT.

 -- procedure: port/set-output-blocking-mode port mode
     Changes the output blocking mode of PORT to be MODE.  Returns an
     unspecified value.

 -- procedure: port/with-output-blocking-mode port mode thunk
     THUNK must be a procedure of no arguments.
     `port/with-output-blocking-mode' binds the output blocking mode of
     PORT to be MODE, executes THUNK, restores the output blocking mode
     of PORT to what it was when `port/with-output-blocking-mode' was
     called, and returns the value that was yielded by THUNK.  This
     binding is performed by `dynamic-wind', which guarantees that the
     output blocking mode is restored if THUNK escapes from its
     continuation.


File: mit-scheme-ref.info,  Node: Terminal Mode,  Prev: Blocking Mode,  Up: Port Primitives

14.9.6 Terminal Mode
--------------------

A port that reads from or writes to a terminal has a "terminal mode";
this is either "cooked" or "raw".  This mode is independent of the
blocking mode: each can be changed independent of the other.
Furthermore, a terminal I/O port has independent terminal modes both
for input and for output.

   A terminal port in cooked mode provides some standard processing to
make the terminal easy to communicate with.  For example, under unix,
cooked mode on input reads from the terminal a line at a time and
provides rubout processing within the line, while cooked mode on output
might translate linefeeds to carriage-return/linefeed pairs.  In
general, the precise meaning of cooked mode is operating-system
dependent, and furthermore might be customizable by means of operating
system utilities.  The basic idea is that cooked mode does whatever is
necessary to make the terminal handle all of the usual user-interface
conventions for the operating system, while keeping the program's
interaction with the port as normal as possible.

   A terminal port in raw mode disables all of that processing.  In raw
mode, characters are directly read from and written to the device
without any translation or interpretation by the operating system.  On
input, characters are available as soon as they are typed, and are not
echoed on the terminal by the operating system.  In general, programs
that put ports in raw mode have to know the details of interacting with
the terminal.  In particular, raw mode is used for writing programs such
as text editors.

   Terminal ports are initially in cooked mode; this can be changed at
any time with the procedures defined in this section.

   These procedures represent cooked mode by the symbol `cooked', and
raw mode by the symbol `raw'.  Additionally, the value `#f' represents
"no mode"; it is the terminal mode of a port that is not a terminal.
An argument called MODE must be one of these three values.  A PORT
argument to any of these procedures may be any port, even if that port
does not support terminal mode; in that case, the port is not modified
in any way.

 -- procedure: port/input-terminal-mode port
     Returns the input terminal mode of PORT.

 -- procedure: port/set-input-terminal-mode port mode
     Changes the input terminal mode of PORT to be MODE.  Returns an
     unspecified value.

 -- procedure: port/with-input-terminal-mode port mode thunk
     THUNK must be a procedure of no arguments.
     `port/with-input-terminal-mode' binds the input terminal mode of
     PORT to be MODE, executes THUNK, restores the input terminal mode
     of PORT to what it was when `port/with-input-terminal-mode' was
     called, and returns the value that was yielded by THUNK.  This
     binding is performed by `dynamic-wind', which guarantees that the
     input terminal mode is restored if THUNK escapes from its
     continuation.

 -- procedure: port/output-terminal-mode port
     Returns the output terminal mode of PORT.

 -- procedure: port/set-output-terminal-mode port mode
     Changes the output terminal mode of PORT to be MODE.  Returns an
     unspecified value.

 -- procedure: port/with-output-terminal-mode port mode thunk
     THUNK must be a procedure of no arguments.
     `port/with-output-terminal-mode' binds the output terminal mode of
     PORT to be MODE, executes THUNK, restores the output terminal mode
     of PORT to what it was when `port/with-output-terminal-mode' was
     called, and returns the value that was yielded by THUNK.  This
     binding is performed by `dynamic-wind', which guarantees that the
     output terminal mode is restored if THUNK escapes from its
     continuation.


File: mit-scheme-ref.info,  Node: Parser Buffers,  Next: Parser Language,  Prev: Port Primitives,  Up: Input/Output

14.10 Parser Buffers
====================

The "parser buffer" mechanism facilitates construction of parsers for
complex grammars.  It does this by providing an input stream with
unbounded buffering and backtracking.  The amount of buffering is under
program control.  The stream can backtrack to any position in the
buffer.

   The mechanism defines two data types: the "parser buffer" and the
"parser-buffer pointer".  A parser buffer is like an input port with
buffering and backtracking.  A parser-buffer pointer is a pointer into
the stream of characters provided by a parser buffer.

   Note that all of the procedures defined here consider a parser buffer
to contain a stream of Unicode characters.

   There are several constructors for parser buffers:

 -- procedure: input-port->parser-buffer port
     Returns a parser buffer that buffers characters read from PORT.

 -- procedure: substring->parser-buffer string start end
     Returns a parser buffer that buffers the characters in the argument
     substring.  This is equivalent to creating a string input port and
     calling `input-port->parser-buffer', but it runs faster and uses
     less memory.

 -- procedure: string->parser-buffer string
     Like `substring->parser-buffer' but buffers the entire string.

 -- procedure: source->parser-buffer source
     Returns a parser buffer that buffers the characters returned by
     calling SOURCE.  SOURCE is a procedure of three arguments: a
     string, a start index, and an end index (in other words, a
     substring specifier).  Each time SOURCE is called, it writes some
     characters in the substring, and returns the number of characters
     written.  When there are no more characters available, it returns
     zero.  It must not return zero in any other circumstance.

   Parser buffers and parser-buffer pointers may be distinguished from
other objects:

 -- procedure: parser-buffer? object
     Returns `#t' if OBJECT is a parser buffer, otherwise returns `#f'.

 -- procedure: parser-buffer-pointer? object
     Returns `#t' if OBJECT is a parser-buffer pointer, otherwise
     returns `#f'.

   Characters can be read from a parser buffer much as they can be read
from an input port.  The parser buffer maintains an internal pointer
indicating its current position in the input stream.  Additionally, the
buffer remembers all characters that were previously read, and can look
at characters arbitrarily far ahead in the stream.  It is this
buffering capability that facilitates complex matching and backtracking.

 -- procedure: read-parser-buffer-char buffer
     Returns the next character in BUFFER, advancing the internal
     pointer past that character.  If there are no more characters
     available, returns `#f' and leaves the internal pointer unchanged.

 -- procedure: peek-parser-buffer-char buffer
     Returns the next character in BUFFER, or `#f' if no characters are
     available.  Leaves the internal pointer unchanged.

 -- procedure: parser-buffer-ref buffer index
     Returns a character in BUFFER.  INDEX is a non-negative integer
     specifying the character to be returned.  If INDEX is zero,
     returns the next available character; if it is one, returns the
     character after that, and so on.  If INDEX specifies a position
     after the last character in BUFFER, returns `#f'.  Leaves the
     internal pointer unchanged.

   The internal pointer of a parser buffer can be read or written:

 -- procedure: get-parser-buffer-pointer buffer
     Returns a parser-buffer pointer object corresponding to the
     internal pointer of BUFFER.

 -- procedure: set-parser-buffer-pointer! buffer pointer
     Sets the internal pointer of BUFFER to the position specified by
     POINTER.  POINTER must have been returned from a previous call of
     `get-parser-buffer-pointer' on BUFFER.  Additionally, if some of
     BUFFER's characters have been discarded by
     `discard-parser-buffer-head!', POINTER must be outside the range
     that was discarded.

 -- procedure: get-parser-buffer-tail buffer pointer
     Returns a newly-allocated string consisting of all of the
     characters in BUFFER that fall between POINTER and BUFFER's
     internal pointer.  POINTER must have been returned from a previous
     call of `get-parser-buffer-pointer' on BUFFER.  Additionally, if
     some of BUFFER's characters have been discarded by
     `discard-parser-buffer-head!', POINTER must be outside the range
     that was discarded.

 -- procedure: discard-parser-buffer-head! buffer
     Discards all characters in BUFFER that have already been read; in
     other words, all characters prior to the internal pointer.  After
     this operation has completed, it is no longer possible to move the
     internal pointer backwards past the current position by calling
     `set-parser-buffer-pointer!'.

   The next rather large set of procedures does conditional matching
against the contents of a parser buffer.  All matching is performed
relative to the buffer's internal pointer, so the first character to be
matched against is the next character that would be returned by
`peek-parser-buffer-char'.  The returned value is always `#t' for a
successful match, and `#f' otherwise.  For procedures whose names do
not end in `-no-advance', a successful match also moves the internal
pointer of the buffer forward to the end of the matched text; otherwise
the internal pointer is unchanged.

 -- procedure: match-parser-buffer-char buffer char
 -- procedure: match-parser-buffer-char-ci buffer char
 -- procedure: match-parser-buffer-not-char buffer char
 -- procedure: match-parser-buffer-not-char-ci buffer char
 -- procedure: match-parser-buffer-char-no-advance buffer char
 -- procedure: match-parser-buffer-char-ci-no-advance buffer char
 -- procedure: match-parser-buffer-not-char-no-advance buffer char
 -- procedure: match-parser-buffer-not-char-ci-no-advance buffer char
     Each of these procedures compares a single character in BUFFER to
     CHAR.  The basic comparison `match-parser-buffer-char' compares
     the character to CHAR using `char=?'.  The procedures whose names
     contain the `-ci' modifier do case-insensitive comparison (i.e.
     they use `char-ci=?').  The procedures whose names contain the
     `not-' modifier are successful if the character _doesn't_ match
     CHAR.

 -- procedure: match-parser-buffer-char-in-set buffer char-set
 -- procedure: match-parser-buffer-char-in-set-no-advance buffer
          char-set
     These procedures compare the next character in BUFFER against
     CHAR-SET using `char-set-member?'.

 -- procedure: match-parser-buffer-string buffer string
 -- procedure: match-parser-buffer-string-ci buffer string
 -- procedure: match-parser-buffer-string-no-advance buffer string
 -- procedure: match-parser-buffer-string-ci-no-advance buffer string
     These procedures match STRING against BUFFER's contents.  The
     `-ci' procedures do case-insensitive matching.

 -- procedure: match-parser-buffer-substring buffer string start end
 -- procedure: match-parser-buffer-substring-ci buffer string start end
 -- procedure: match-parser-buffer-substring-no-advance buffer string
          start end
 -- procedure: match-parser-buffer-substring-ci-no-advance buffer
          string start end
     These procedures match the specified substring against BUFFER's
     contents.  The `-ci' procedures do case-insensitive matching.

   The remaining procedures provide information that can be used to
identify locations in a parser buffer's stream.

 -- procedure: parser-buffer-position-string pointer
     Returns a string describing the location of POINTER in terms of
     its character and line indexes.  This resulting string is meant to
     be presented to an end user in order to direct their attention to a
     feature in the input stream.  In this string, the indexes are
     presented as one-based numbers.

     POINTER may alternatively be a parser buffer, in which case it is
     equivalent to having specified the buffer's internal pointer.

 -- procedure: parser-buffer-pointer-index pointer
 -- procedure: parser-buffer-pointer-line pointer
     Returns the character or line index, respectively, of POINTER.
     Both indexes are zero-based.


File: mit-scheme-ref.info,  Node: Parser Language,  Next: XML Support,  Prev: Parser Buffers,  Up: Input/Output

14.11 Parser Language
=====================

Although it is possible to write parsers using the parser-buffer
abstraction (*note Parser Buffers::), it is tedious.  The problem is
that the abstraction isn't closely matched to the way that people think
about syntactic structures.  In this section, we introduce a
higher-level mechanism that greatly simplifies the implementation of a
parser.

   The "parser language" described here allows the programmer to write
BNF-like specifications that are translated into efficient Scheme code
at compile time.  The language is declarative, but it can be freely
mixed with Scheme code; this allows the parsing of grammars that aren't
conveniently described in the language.

   The language also provides backtracking.  For example, this
expression matches any sequence of alphanumeric characters followed by
a single alphabetic character:

     (*matcher
      (seq (* (char-set char-set:alphanumeric))
           (char-set char-set:alphabetic)))

The way that this works is that the matcher matches alphanumeric
characters in the input stream until it finds a non-alphanumeric
character.  It then tries to match an alphabetic character, which of
course fails.  At this point, if it matched at least one alphanumeric
character, it _backtracks_: the last matched alphanumeric is
"unmatched", and it again attempts to match an alphabetic character.
The backtracking can be arbitrarily deep; the matcher will continue to
back up until it finds a way to match the remainder of the expression.

   So far, this sounds a lot like regular-expression matching (*note
Regular Expressions::).  However, there are some important differences.

   * The parser language uses a Scheme-like syntax that is easier to
     read and write than regular-expression notation.

   * The language provides macros so that common syntactic constructs
     can be abstracted.

   * The language mixes easily with Scheme code, allowing the full
     power of Scheme to be applied to program around limitations in the
     parser language.

   * The language provides expressive facilities for converting syntax
     into parsed structure.  It also makes it easy to convert parsed
     strings into meaningful objects (e.g. numbers).

   * The language is compiled into machine language; regular expressions
     are usually interpreted.

   Here is an example that shows off several of the features of the
parser language.  The example is a parser for XML start tags:

     (*parser
      (with-pointer p
        (seq "<"
             parse-name
             parse-attribute-list
             (alt (match ">")
                  (match "/>")
                  (sexp
                   (lambda (b)
                     (error
                      (string-append
                       "Unterminated start tag at "
                       (parser-buffer-position-string p)))))))))

This shows that the basic description of a start tag is very similar to
its BNF.  Non-terminal symbols `parse-name' and `parse-attribute-list'
do most of the work, and the noise strings `"<"' and `">"' are the
syntactic markers delimiting the form.  There are two alternate endings
for start tags, and if the parser doesn't find either of the endings,
the Scheme code (wrapped in `sexp') is run to signal an error.  The
error procedure `perror' takes a pointer `p', which it uses to indicate
the position in the input stream at which the error occurred.  In this
case, that is the beginning of the start tag, i.e. the position of the
leading `"<"' marker.

   This example still looks pretty complicated, mostly due to the
error-signalling code.  In practice, this is abstracted into a macro,
after which the expression is quite succinct:

     (*parser
      (bracket "start tag"
          (seq (noise (string "<")) parse-name)
          (match (alt (string ">") (string "/>")))
        parse-attribute-list))

The `bracket' macro captures the pattern of a bracketed item, and hides
much of the detail.

   The parser language actually consists of two languages: one for
defining matchers, and one for defining parsers.  The languages are
intentionally very similar, and are meant to be used together.  Each
sub-language is described below in its own section.

   The parser language is a run-time-loadable option; to use it, execute

     (load-option '*parser)
   
once before compiling any code that uses the language.

* Menu:

* *Matcher::
* *Parser::
* Parser-language Macros::


File: mit-scheme-ref.info,  Node: *Matcher,  Next: *Parser,  Prev: Parser Language,  Up: Parser Language

14.11.1 *Matcher
----------------

The "matcher language" is a declarative language for specifying a
"matcher procedure".  A matcher procedure is a procedure that accepts a
single parser-buffer argument and returns a boolean value indicating
whether the match it performs was successful.  If the match succeeds,
the internal pointer of the parser buffer is moved forward over the
matched text.  If the match fails, the internal pointer is unchanged.

   For example, here is a matcher procedure that matches the character
`a':

     (lambda (b) (match-parser-buffer-char b #\a))

Here is another example that matches two given characters, C1 and C2,
in sequence:

     (lambda (b)
       (let ((p (get-parser-buffer-pointer b)))
         (if (match-parser-buffer-char b C1)
             (if (match-parser-buffer-char b C2)
                 #t
                 (begin
                   (set-parser-buffer-pointer! b p)
                   #f))
             #f)))

This is code is clear, but has lots of details that get in the way of
understanding what it is doing.  Here is the same example in the
matcher language:

     (*matcher (seq (char C1) (char C2)))

This is much simpler and more intuitive.  And it generates virtually
the same code:

     (pp (*matcher (seq (char c1) (char c2))))
     -| (lambda (#[b1])
     -|   (let ((#[p1] (get-parser-buffer-pointer #[b1])))
     -|     (and (match-parser-buffer-char #[b1] c1)
     -|          (if (match-parser-buffer-char #[b1] c2)
     -|              #t
     -|              (begin
     -|                (set-parser-buffer-pointer! #[b1] #[p1])
     -|                #f)))))

   Now that we have seen an example of the language, it's time to look
at the detail.  The `*matcher' special form is the interface between
the matcher language and Scheme.

 -- special form: *matcher mexp
     The operand MEXP is an expression in the matcher language.  The
     `*matcher' expression expands into Scheme code that implements a
     matcher procedure.

   Here are the predefined matcher expressions.  New matcher expressions
can be defined using the macro facility (*note Parser-language
Macros::).  We will start with the primitive expressions.

 -- matcher expression: char expression
 -- matcher expression: char-ci expression
 -- matcher expression: not-char expression
 -- matcher expression: not-char-ci expression
     These expressions match a given character.  In each case, the
     EXPRESSION operand is a Scheme expression that must evaluate to a
     character at run time.  The `-ci' expressions do case-insensitive
     matching.  The `not-' expressions match any character other than
     the given one.

 -- matcher expression: string expression
 -- matcher expression: string-ci expression
     These expressions match a given string.  The EXPRESSION operand is
     a Scheme expression that must evaluate to a string at run time.
     The `string-ci' expression does case-insensitive matching.

 -- matcher expression: char-set expression
     These expressions match a single character that is a member of a
     given character set.  The EXPRESSION operand is a Scheme expression
     that must evaluate to a character set at run time.

 -- matcher expression: end-of-input
     The `end-of-input' expression is successful only when there are no
     more characters available to be matched.

 -- matcher expression: discard-matched
     The `discard-matched' expression always successfully matches the
     null string.  However, it isn't meant to be used as a matching
     expression; it is used for its effect.  `discard-matched' causes
     all of the buffered text prior to this point to be discarded (i.e.
     it calls `discard-parser-buffer-head!' on the parser buffer).

     Note that `discard-matched' may not be used in certain places in a
     matcher expression.  The reason for this is that it deliberately
     discards information needed for backtracking, so it may not be
     used in a place where subsequent backtracking will need to back
     over it.  As a rule of thumb, use `discard-matched' only in the
     last operand of a `seq' or `alt' expression (including any `seq' or
     `alt' expressions in which it is indirectly contained).

   In addition to the above primitive expressions, there are two
convenient abbreviations.  A character literal (e.g. `#\A') is a legal
primitive expression, and is equivalent to a `char' expression with
that literal as its operand (e.g. `(char #\A)').  Likewise, a string
literal is equivalent to a `string' expression (e.g. `(string "abc")').

   Next there are several combinator expressions.  These closely
correspond to similar combinators in regular expressions.  Parameters
named MEXP are arbitrary expressions in the matcher language.

 -- matcher expression: seq mexp ...
     This matches each MEXP operand in sequence.  For example,

          (seq (char-set char-set:alphabetic)
               (char-set char-set:numeric))

     matches an alphabetic character followed by a numeric character,
     such as `H4'.

     Note that if there are no MEXP operands, the `seq' expression
     successfully matches the null string.

 -- matcher expression: alt mexp ...
     This attempts to match each MEXP operand in order from left to
     right.  The first one that successfully matches becomes the match
     for the entire `alt' expression.

     The `alt' expression participates in backtracking.  If one of the
     MEXP operands matches, but the overall match in which this
     expression is embedded fails, the backtracking mechanism will cause
     the `alt' expression to try the remaining MEXP operands.  For
     example, if the expression

          (seq (alt "ab" "a") "b")

     is matched against the text `abc', the `alt' expression will
     initially match its first operand.  But it will then fail to match
     the second operand of the `seq' expression.  This will cause the
     `alt' to be restarted, at which time it will match `a', and the
     overall match will succeed.

     Note that if there are no MEXP operands, the `alt' match will
     always fail.

 -- matcher expression: * mexp
     This matches zero or more occurrences of the MEXP operand.
     (Consequently this match always succeeds.)

     The `*' expression participates in backtracking; if it matches N
     occurrences of MEXP, but the overall match fails, it will
     backtrack to N-1 occurrences and continue.  If the overall match
     continues to fail, the `*' expression will continue to backtrack
     until there are no occurrences left.

 -- matcher expression: + mexp
     This matches one or more occurrences of the MEXP operand.  It is
     equivalent to

          (seq MEXP (* MEXP))

 -- matcher expression: ? mexp
     This matches zero or one occurrences of the MEXP operand.  It is
     equivalent to

          (alt MEXP (seq))

 -- matcher expression: sexp expression
     The `sexp' expression allows arbitrary Scheme code to be embedded
     inside a matcher.  The EXPRESSION operand must evaluate to a
     matcher procedure at run time; the procedure is called to match the
     parser buffer.  For example,

          (*matcher
           (seq "a"
                (sexp parse-foo)
                "b"))

     expands to

          (lambda (#[b1])
            (let ((#[p1] (get-parser-buffer-pointer #[b1])))
              (and (match-parser-buffer-char #[b1] #\a)
                   (if (parse-foo #[b1])
                       (if (match-parser-buffer-char #[b1] #\b)
                           #t
                           (begin
                             (set-parser-buffer-pointer! #[b1] #[p1])
                             #f))
                       (begin
                         (set-parser-buffer-pointer! #[b1] #[p1])
                         #f)))))

     The case in which EXPRESSION is a symbol is so common that it has
     an abbreviation: `(sexp SYMBOL)' may be abbreviated as just SYMBOL.

 -- matcher expression: with-pointer identifier mexp
     The `with-pointer' expression fetches the parser buffer's internal
     pointer (using `get-parser-buffer-pointer'), binds it to
     IDENTIFIER, and then matches the pattern specified by MEXP.
     IDENTIFIER must be a symbol.

     This is meant to be used on conjunction with `sexp', as a way to
     capture a pointer to a part of the input stream that is outside the
     `sexp' expression.  An example of the use of `with-pointer'
     appears above (*note with-pointer example::).


File: mit-scheme-ref.info,  Node: *Parser,  Next: Parser-language Macros,  Prev: *Matcher,  Up: Parser Language

14.11.2 *Parser
---------------

The "parser language" is a declarative language for specifying a
"parser procedure".  A parser procedure is a procedure that accepts a
single parser-buffer argument and parses some of the input from the
buffer.  If the parse is successful, the procedure returns a vector of
objects that are the result of the parse, and the internal pointer of
the parser buffer is advanced past the input that was parsed.  If the
parse fails, the procedure returns `#f' and the internal pointer is
unchanged.  This interface is much like that of a matcher procedure,
except that on success the parser procedure returns a vector of values
rather than `#t'.

   The `*parser' special form is the interface between the parser
language and Scheme.

 -- special form: *parser pexp
     The operand PEXP is an expression in the parser language.  The
     `*parser' expression expands into Scheme code that implements a
     parser procedure.

   There are several primitive expressions in the parser language.  The
first two provide a bridge to the matcher language (*note *Matcher::):

 -- parser expression: match mexp
     The `match' expression performs a match on the parser buffer.  The
     match to be performed is specified by MEXP, which is an expression
     in the matcher language.  If the match is successful, the result
     of the `match' expression is a vector of one element: a string
     containing that text.

 -- parser expression: noise mexp
     The `noise' expression performs a match on the parser buffer.  The
     match to be performed is specified by MEXP, which is an expression
     in the matcher language.  If the match is successful, the result
     of the `noise' expression is a vector of zero elements.  (In other
     words, the text is matched and then thrown away.)

     The MEXP operand is often a known character or string, so in the
     case that MEXP is a character or string literal, the `noise'
     expression can be abbreviated as the literal.  In other words,
     `(noise "foo")' can be abbreviated just `"foo"'.

 -- parser expression: values expression ...
     Sometimes it is useful to be able to insert arbitrary values into
     the parser result.  The `values' expression supports this.  The
     EXPRESSION arguments are arbitrary Scheme expressions that are
     evaluated at run time and returned in a vector.  The `values'
     expression always succeeds and never modifies the internal pointer
     of the parser buffer.

 -- parser expression: discard-matched
     The `discard-matched' expression always succeeds, returning a
     vector of zero elements.  In all other respects it is identical to
     the `discard-matched' expression in the matcher language.

   Next there are several combinator expressions.  Parameters named
PEXP are arbitrary expressions in the parser language.  The first few
combinators are direct equivalents of those in the matcher language.

 -- parser expression: seq pexp ...
     The `seq' expression parses each of the PEXP operands in order.
     If all of the PEXP operands successfully match, the result is the
     concatenation of their values (by `vector-append').

 -- parser expression: alt pexp ...
     The `alt' expression attempts to parse each PEXP operand in order
     from left to right.  The first one that successfully parses
     produces the result for the entire `alt' expression.

     Like the `alt' expression in the matcher language, this expression
     participates in backtracking.

 -- parser expression: * pexp
     The `*' expression parses zero or more occurrences of PEXP.  The
     results of the parsed occurrences are concatenated together (by
     `vector-append') to produce the expression's result.

     Like the `*' expression in the matcher language, this expression
     participates in backtracking.

 -- parser expression: + pexp
     The `*' expression parses one or more occurrences of PEXP.  It is
     equivalent to

          (seq PEXP (* PEXP))

 -- parser expression: ? pexp
     The `*' expression parses zero or one occurrences of PEXP.  It is
     equivalent to

          (alt PEXP (seq))

   The next three expressions do not have equivalents in the matcher
language.  Each accepts a single PEXP argument, which is parsed in the
usual way.  These expressions perform transformations on the returned
values of a successful match.

 -- parser expression: transform expression pexp
     The `transform' expression performs an arbitrary transformation of
     the values returned by parsing PEXP.  EXPRESSION is a Scheme
     expression that must evaluate to a procedure at run time.  If PEXP
     is successfully parsed, the procedure is called with the vector of
     values as its argument, and must return a vector or `#f'.  If it
     returns a vector, the parse is successful, and those are the
     resulting values.  If it returns `#f', the parse fails and the
     internal pointer of the parser buffer is returned to what it was
     before PEXP was parsed.

     For example:

          (transform (lambda (v) (if (= 0 (vector-length v)) #f v)) ...)

 -- parser expression: encapsulate expression pexp
     The `encapsulate' expression transforms the values returned by
     parsing PEXP into a single value.  EXPRESSION is a Scheme
     expression that must evaluate to a procedure at run time.  If PEXP
     is successfully parsed, the procedure is called with the vector of
     values as its argument, and may return any Scheme object.  The
     result of the `encapsulate' expression is a vector of length one
     containing that object.  (And consequently `encapsulate' doesn't
     change the success or failure of PEXP, only its value.)

     For example:

          (encapsulate vector->list ...)

 -- parser expression: map expression pexp
     The `map' expression performs a per-element transform on the
     values returned by parsing PEXP.  EXPRESSION is a Scheme
     expression that must evaluate to a procedure at run time.  If PEXP
     is successfully parsed, the procedure is mapped (by `vector-map')
     over the values returned from the parse.  The mapped values are
     returned as the result of the `map' expression.  (And consequently
     `map' doesn't change the success or failure of PEXP, nor the
     number of values returned.)

     For example:

          (map string->symbol ...)

   Finally, as in the matcher language, we have `sexp' and
`with-pointer' to support embedding Scheme code in the parser.

 -- parser expression: sexp expression
     The `sexp' expression allows arbitrary Scheme code to be embedded
     inside a parser.  The EXPRESSION operand must evaluate to a parser
     procedure at run time; the procedure is called to parse the parser
     buffer.  This is the parser-language equivalent of the `sexp'
     expression in the matcher language.

     The case in which EXPRESSION is a symbol is so common that it has
     an abbreviation: `(sexp SYMBOL)' may be abbreviated as just SYMBOL.

 -- parser expression: with-pointer identifier pexp
     The `with-pointer' expression fetches the parser buffer's internal
     pointer (using `get-parser-buffer-pointer'), binds it to
     IDENTIFIER, and then parses the pattern specified by PEXP.
     IDENTIFIER must be a symbol.  This is the parser-language
     equivalent of the `with-pointer' expression in the matcher
     language.


File: mit-scheme-ref.info,  Node: Parser-language Macros,  Prev: *Parser,  Up: Parser Language

14.11.3 Parser-language Macros
------------------------------

The parser and matcher languages provide a macro facility so that
common patterns can be abstracted.  The macro facility allows new
expression types to be independently defined in the two languages.  The
macros are defined in hierarchically organized tables, so that
different applications can have private macro bindings.

 -- special form: define-*matcher-macro formals expression
 -- special form: define-*parser-macro formals expression
     These special forms are used to define macros in the matcher and
     parser language, respectively.  FORMALS is like the FORMALS list
     of a `define' special form, and EXPRESSION is a Scheme expression.

     If FORMALS is a list (or improper list) of symbols, the first
     symbol in the list is the name of the macro, and the remaining
     symbols are interpreted as the FORMALS of a lambda expression.  A
     lambda expression is formed by combining the latter FORMALS with
     the EXPRESSION, and this lambda expression, when evaluated, becomes
     the "expander".  The defined macro accepts the same number of
     operands as the expander.  A macro instance is expanded by applying
     the expander to the list of operands; the result of the
     application is interpreted as a replacement expression for the
     macro instance.

     If FORMALS is a symbol, it is the name of the macro.  In this
     case, the expander is a procedure of no arguments whose body is
     EXPRESSION.  When the FORMALS symbol appears by itself as an
     expression in the language, the expander is called with no
     arguments, and the result is interpreted as a replacement
     expression for the symbol.

 -- procedure: define-*matcher-expander identifier expander
 -- procedure: define-*parser-expander identifier expander
     These procedures provide a procedural interface to the
     macro-definition mechanism.  IDENTIFIER must be a symbol, and
     EXPANDER must be an expander procedure, as defined above.
     Instances of the `define-*matcher-macro' and
     `define-*parser-macro' special forms expand into calls to these
     procedures.

   The remaining procedures define the interface to the parser-macros
table abstraction.  Each parser-macro table has a separate binding
space for macros in the matcher and parser languages.  However, the
table inherits bindings from one specified table; it's not possible to
inherit matcher-language bindings from one table and parser-language
bindings from another.

 -- procedure: make-parser-macros parent-table
     Create and return a new parser-macro table that inherits from
     PARENT-TABLE.  PARENT-TABLE must be either a parser-macro table,
     or `#f'; usually it is specified as the value of
     `global-parser-macros'.

 -- procedure: parser-macros? object
     This is a predicate for parser-macro tables.

 -- procedure: global-parser-macros
     Return the global parser-macro table.  This table is predefined and
     contains all of the bindings documented here.

   There is a "current" table at all times, and macro definitions are
always placed in this table.  By default, the current table is the
global macro table, but the following procedures allow this to be
changed.

 -- procedure: current-parser-macros
     Return the current parser-macro table.

 -- procedure: set-current-parser-macros! table
     Change the current parser-macro table to TABLE, which must satisfy
     `parser-macros?'.

 -- procedure: with-current-parser-macros table thunk
     Bind the current parser-macro table to TABLE, call THUNK with no
     arguments, then restore the original table binding.  The value
     returned by THUNK is the returned as the value of this procedure.
     TABLE must satisfy `parser-macros?', and THUNK must be a procedure
     of no arguments.


File: mit-scheme-ref.info,  Node: XML Support,  Prev: Parser Language,  Up: Input/Output

14.12 XML Support
=================

MIT/GNU Scheme provides a simple non-validating XML parser.  This
parser is believed to be conformant with XML 1.0.  It passes all of the
tests in the "xmltest" directory of the XML conformance tests (dated
2001-03-15).  The parser supports XML namespaces; it doesn't support
external document type declarations (DTDs), and it doesn't yet support
XML 1.1.  The output of the parser is a record tree that closely
reflects the structure of the XML document.

   MIT/GNU Scheme also provides support for writing an XML record tree
to an output port.  There is no guarantee that parsing an XML document
and writing it back out will make a verbatim copy of the document.  The
output will be semantically identical but may have small syntactic
differences.  For example, entities are substituted during the parsing
process.

   The purpose of the XML support is to provide a mechanism for reading
and writing simple XML documents.  In the future this support may be
further developed to support a standard interface such as DOM or SAX.

   The XML support is a run-time-loadable option; to use it, execute

     (load-option 'xml)
   
once before running any code that uses it.

* Menu:

* XML Input::
* XML Output::
* XML Names::
* XML Structure::


File: mit-scheme-ref.info,  Node: XML Input,  Next: XML Output,  Prev: XML Support,  Up: XML Support

14.12.1 XML Input
-----------------

The primary entry point for the XML parser is `read-xml', which reads
characters from a port and returns an XML document record.  The
character coding of the input is determined by reading some of the
input stream and looking for a byte order mark and/or an encoding in
the XML declaration.  We support all ISO 8859 codings, as well as
UTF-8, UTF-16, and UTF-32.

   When an XHTML document is read, the parser provides entity
definitions for all of the named XHTML characters; for example, it
defines `&nbsp;' and `&copy;'.  In order for a document to be
recognized as XHTML, it must contain an XHTML DTD, such as this:

     <!DOCTYPE html
               PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

At present the parser recognizes XHTML Strict 1.0 and XHTML 1.1
documents.

 -- procedure: read-xml port [pi-handlers]
     Read an XML document from PORT and return the corresponding XML
     document record.

     PI-HANDLERS, if specified, must be an association list.  Each
     element of PI-HANDLERS must be a list of two elements: a symbol
     and a procedure.  When the parser encounters processing
     instructions with a name that appears in PI-HANDLERS, the
     procedure is called with one argument, which is the text of the
     processing instructions.  The procedure must return a list of XML
     structure records that are legal for the context of the processing
     instructions.

 -- procedure: read-xml-file pathname [pi-handlers]
     This convenience procedure simplifies reading XML from a file.  It
     is roughly equivalent to

          (define (read-xml-file pathname #!optional pi-handlers)
            (call-with-input-file pathname
              (lambda (port)
                (read-xml port pi-handlers))))

 -- procedure: string->xml string [start [end [pi-handlers]]]
     This convenience procedure simplifies reading XML from a string.
     The STRING argument may be a string or a wide string.  It is
     roughly equivalent to

          (define (string->xml string #!optional start end pi-handlers)
            (read-xml (open-input-string string start end)
                      pi-handlers))


File: mit-scheme-ref.info,  Node: XML Output,  Next: XML Names,  Prev: XML Input,  Up: XML Support

14.12.2 XML Output
------------------

The following procedures serialize XML document records into character
sequences.  All are virtually identical except for the way that the
character sequence is represented.

   Each procedure will accept either an `xml-document' record or any of
the other XML record types.  This makes it possible to write fragments
of XML documents, although you should keep in mind that such fragments
aren't documents and won't generally be accepted by any XML parser.

   If the XML being written is an `xml-document' record, the procedures
`write-xml' and `write-xml-file' will look for a contained
`xml-declaration' record and its `encoding' attribute.  If the
`encoding' is a supported value, the output will be encoded as
specified; otherwise it will be encoded as UTF-8.

   When an XHTML document record is written, named XHTML characters are
translated into their corresponding entities.  For example, the
character `#\U+00A0' is written as `&nbsp;'.  In order for an XML
document record to be recognized as XHTML, it must have a DTD record
that satisfies the predicate `html-dtd?'.

 -- procedure: write-xml xml port
     Write XML to PORT.  Note that character encoding will only be done
     if PORT supports it.

 -- procedure: write-xml-file xml pathname
     Write XML to the file specified by PATHNAME.  Roughly equivalent to

          (define (write-xml-file xml pathname)
            (call-with-output-file pathname
              (lambda (port)
                (write-xml xml port))))

 -- procedure: xml->wide-string xml
     Convert XML to a wide string.  No character encoding is used,
     since wide strings can represent all characters without encoding.
     Roughly equivalent to

          (define (xml->wide-string xml)
            (call-with-wide-output-string
             (lambda (port)
               (write-xml xml port))))

 -- procedure: xml->string xml
     Convert XML to a character string encoded as UTF-8.  Roughly
     equivalent to

          (define (xml->string xml)
            (wide-string->utf8-string (xml->wide-string xml)))

