deprecate generalized vectors in favor of arrays
[bpt/guile.git] / doc / ref / api-compound.texi
index f190013..ab2bd30 100644 (file)
@@ -1,10 +1,9 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
-@c   Free Software Foundation, Inc.
+@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+@c   2007, 2009, 2010, 2011, 2012, 2013  Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
-@page
 @node Compound Data Types
 @section Compound Data Types
 
@@ -22,14 +21,16 @@ values can be looked up within them.
 * Pairs::                       Scheme's basic building block.
 * Lists::                       Special list functions supported by Guile.
 * Vectors::                     One-dimensional arrays of Scheme objects.
-* Uniform Numeric Vectors::     Vectors with elements of a single numeric type.
 * Bit Vectors::                 Vectors of bits.
-* Generalized Vectors::         Treating all vector-like things uniformly.
 * Arrays::                      Matrices, etc.
-* Records::                     
-* Structures::                  
+* VLists::                      Vector-like lists.
+* Record Overview::             Walking through the maze of record APIs.
+* SRFI-9 Records::              The standard, recommended record API.
+* Records::                     Guile's historical record API.
+* Structures::                  Low-level record representation.
 * Dictionary Types::            About dictionary types in general.
 * Association Lists::           List-based dictionaries.
+* VHashes::                     VList-based dictionaries.   
 * Hash Tables::                 Table-based dictionaries.
 @end menu
 
@@ -63,8 +64,8 @@ parser would not be able to figure out where to split the tokens.
 
 But beware, if you want to try out these examples, you have to
 @dfn{quote} the expressions.  More information about quotation is
-available in the section (REFFIXME).  The correct way to try these
-examples is as follows.
+available in the section @ref{Expression Syntax}.  The correct way
+to try these examples is as follows.
 
 @lisp
 '(1 . 2)
@@ -103,10 +104,14 @@ Return 1 when @var{x} is a pair; otherwise return 0.
 The two parts of a pair are traditionally called @dfn{car} and
 @dfn{cdr}.  They can be retrieved with procedures of the same name
 (@code{car} and @code{cdr}), and can be modified with the procedures
-@code{set-car!} and @code{set-cdr!}.  Since a very common operation in
-Scheme programs is to access the car of a pair, or the car of the cdr of
-a pair, etc., the procedures called @code{caar}, @code{cadr} and so on
-are also predefined.
+@code{set-car!} and @code{set-cdr!}.
+
+Since a very common operation in Scheme programs is to access the car of
+a car of a pair, or the car of the cdr of a pair, etc., the procedures
+called @code{caar}, @code{cadr} and so on are also predefined.  However,
+using these procedures is often detrimental to readability, and
+error-prone.  Thus, accessing the contents of a list is usually better
+achieved using pattern matching techniques (@pxref{Pattern Matching}).
 
 @rnindex car
 @rnindex cdr
@@ -117,6 +122,16 @@ are also predefined.
 Return the car or the cdr of @var{pair}, respectively.
 @end deffn
 
+@deftypefn  {C Macro} SCM SCM_CAR (SCM pair)
+@deftypefnx {C Macro} SCM SCM_CDR (SCM pair)
+These two macros are the fastest way to access the car or cdr of a
+pair; they can be thought of as compiling into a single memory
+reference.
+
+These macros do no checking at all.  The argument @var{pair} must be a
+valid pair.
+@end deftypefn
+
 @deffn  {Scheme Procedure} cddr pair
 @deffnx {Scheme Procedure} cdar pair
 @deffnx {Scheme Procedure} cadr pair
@@ -179,6 +194,11 @@ for example @code{caddr} could be defined by
 @lisp
 (define caddr (lambda (x) (car (cdr (cdr x)))))
 @end lisp
+
+@code{cadr}, @code{caddr} and @code{cadddr} pick out the second, third
+or fourth elements of a list, respectively.  SRFI-1 provides the same
+under the names @code{second}, @code{third} and @code{fourth}
+(@pxref{SRFI-1 Selectors}).
 @end deffn
 
 @rnindex set-car!
@@ -263,9 +283,10 @@ up a list.  An example will clear that up:
 ()
 @end lisp
 
-This example also shows that lists have to be quoted (REFFIXME) when
-written, because they would otherwise be mistakingly taken as procedure
-applications (@pxref{Simple Invocation}).
+This example also shows that lists have to be quoted when written
+(@pxref{Expression Syntax}), because they would otherwise be
+mistakingly taken as procedure applications (@pxref{Simple
+Invocation}).
 
 
 @node List Predicates
@@ -310,7 +331,7 @@ the last pair of the list.
 @c  no-op since it does nothing but return the list the caller must
 @c  have already created.
 @c
-@deffn {Scheme Procedure} list elem1 @dots{} elemN
+@deffn {Scheme Procedure} list elem @dots{}
 @deffnx {C Function} scm_list_1 (elem1)
 @deffnx {C Function} scm_list_2 (elem1, elem2)
 @deffnx {C Function} scm_list_3 (elem1, elem2, elem3)
@@ -318,11 +339,11 @@ the last pair of the list.
 @deffnx {C Function} scm_list_5 (elem1, elem2, elem3, elem4, elem5)
 @deffnx {C Function} scm_list_n (elem1, @dots{}, elemN, @nicode{SCM_UNDEFINED})
 @rnindex list
-Return a new list containing elements @var{elem1} to @var{elemN}.
+Return a new list containing elements @var{elem} @enddots{}.
 
 @code{scm_list_n} takes a variable number of arguments, terminated by
 the special @code{SCM_UNDEFINED}.  That final @code{SCM_UNDEFINED} is
-not included in the list.  None of @var{elem1} to @var{elemN} can
+not included in the list.  None of @var{elem} @dots{} can
 themselves be @code{SCM_UNDEFINED}, or @code{scm_list_n} will
 terminate at that point.
 @end deffn
@@ -414,12 +435,14 @@ pairs.  This is why you should be careful when using the side-effecting
 variants.
 
 @rnindex append
-@deffn {Scheme Procedure} append lst1 @dots{} lstN
-@deffnx {Scheme Procedure} append! lst1 @dots{} lstN
+@deffn {Scheme Procedure} append lst @dots{} obj
+@deffnx {Scheme Procedure} append
+@deffnx {Scheme Procedure} append! lst @dots{} obj
+@deffnx {Scheme Procedure} append!
 @deffnx {C Function} scm_append (lstlst)
 @deffnx {C Function} scm_append_x (lstlst)
-Return a list comprising all the elements of lists @var{lst1} to
-@var{lstN}.
+Return a list comprising all the elements of lists @var{lst} @dots{}
+@var{obj}.  If called with no arguments, return the empty list.
 
 @lisp
 (append '(x) '(y))          @result{}  (x y)
@@ -427,7 +450,7 @@ Return a list comprising all the elements of lists @var{lst1} to
 (append '(a (b)) '((c)))    @result{}  (a (b) (c))
 @end lisp
 
-The last argument @var{lstN} may actually be any object; an improper
+The last argument @var{obj} may actually be any object; an improper
 list results if the last argument is not a proper list.
 
 @lisp
@@ -436,11 +459,11 @@ list results if the last argument is not a proper list.
 @end lisp
 
 @code{append} doesn't modify the given lists, but the return may share
-structure with the final @var{lstN}.  @code{append!} modifies the
+structure with the final @var{obj}.  @code{append!} modifies the
 given lists to form its return.
 
 For @code{scm_append} and @code{scm_append_x}, @var{lstlst} is a list
-of the list operands @var{lst1} @dots{} @var{lstN}.  That @var{lstlst}
+of the list operands @var{lst} @dots{} @var{obj}.  That @var{lstlst}
 itself is not modified or used in the return.
 @end deffn
 
@@ -454,7 +477,7 @@ Return a list comprising the elements of @var{lst}, in reverse order.
 @code{reverse} constructs a new list, @code{reverse!} modifies
 @var{lst} in constructing its return.
 
-For @code{reverse!}, the optional @var{newtail} is appended to to the
+For @code{reverse!}, the optional @var{newtail} is appended to the
 result.  @var{newtail} isn't reversed, it simply becomes the list
 tail.  For @code{scm_reverse_x}, the @var{newtail} parameter is
 mandatory, but can be @code{SCM_EOL} if no further tail is required.
@@ -487,7 +510,7 @@ Return a newly-created copy of @var{lst} with elements
 @deffn {Scheme Procedure} delv item lst
 @deffnx {C Function} scm_delv (item, lst)
 Return a newly-created copy of @var{lst} with elements
-@code{eqv?}  to @var{item} removed.  This procedure mirrors
+@code{eqv?} to @var{item} removed.  This procedure mirrors
 @code{memv}: @code{delv} compares elements of @var{lst} against
 @var{item} with @code{eqv?}.
 @end deffn
@@ -495,9 +518,13 @@ Return a newly-created copy of @var{lst} with elements
 @deffn {Scheme Procedure} delete item lst
 @deffnx {C Function} scm_delete (item, lst)
 Return a newly-created copy of @var{lst} with elements
-@code{equal?}  to @var{item} removed.  This procedure mirrors
+@code{equal?} to @var{item} removed.  This procedure mirrors
 @code{member}: @code{delete} compares elements of @var{lst}
 against @var{item} with @code{equal?}.
+
+See also SRFI-1 which has an extended @code{delete} (@ref{SRFI-1
+Deleting}), and also an @code{lset-difference} which can delete
+multiple @var{item}s in one call (@ref{SRFI-1 Set Operations}).
 @end deffn
 
 @deffn {Scheme Procedure} delq! item lst
@@ -542,7 +569,9 @@ predicate @var{pred}.  The elements in the result list have the same
 order as in @var{lst}.  The order in which @var{pred} is applied to
 the list elements is not specified.
 
-@code{filter!} is allowed, but not required to modify the structure of
+@code{filter} does not change @var{lst}, but the result may share a
+tail with it.  @code{filter!} may modify @var{lst} to construct its
+return.
 @end deffn
 
 @node List Searching
@@ -585,6 +614,9 @@ the non-empty lists returned by @code{(list-tail @var{lst}
 @var{k})} for @var{k} less than the length of @var{lst}.  If
 @var{x} does not occur in @var{lst}, then @code{#f} (not the
 empty list) is returned.
+
+See also SRFI-1 which has an extended @code{member} function
+(@ref{SRFI-1 Searching}).
 @end deffn
 
 
@@ -620,6 +652,8 @@ and the result(s) of the procedure applications are thrown away.  The
 return value is not specified.
 @end deffn
 
+See also SRFI-1 which extends these functions to take lists of unequal
+lengths (@ref{SRFI-1 Fold and Map}).
 
 @node Vectors
 @subsection Vectors
@@ -644,6 +678,7 @@ and that most array procedures operate happily on vectors
 * Vector Creation::             Dynamic vector creation and validation.
 * Vector Accessors::            Accessing and modifying vector contents.
 * Vector Accessing from C::     Ways to work with vectors from C.
+* Uniform Numeric Vectors::     Vectors of unboxed numeric values.
 @end menu
 
 
@@ -681,7 +716,7 @@ thus created is determined implicitly by the number of arguments given.
 
 @rnindex vector
 @rnindex list->vector
-@deffn {Scheme Procedure} vector . l
+@deffn {Scheme Procedure} vector arg @dots{}
 @deffnx {Scheme Procedure} list->vector l
 @deffnx {C Function} scm_vector (l)
 Return a newly allocated vector composed of the
@@ -747,19 +782,19 @@ in the vector.
 
 @rnindex vector-length
 @deffn {Scheme Procedure} vector-length vector
-@deffnx {C Function} scm_vector_length vector
+@deffnx {C Function} scm_vector_length (vector)
 Return the number of elements in @var{vector} as an exact integer.
 @end deffn
 
-@deftypefn {C Function} size_t scm_c_vector_length (SCM v)
-Return the number of elements in @var{vector} as a @code{size_t}.
+@deftypefn {C Function} size_t scm_c_vector_length (SCM vec)
+Return the number of elements in @var{vec} as a @code{size_t}.
 @end deftypefn
 
 @rnindex vector-ref
-@deffn {Scheme Procedure} vector-ref vector k
-@deffnx {C Function} scm_vector_ref vector k
-Return the contents of position @var{k} of @var{vector}.
-@var{k} must be a valid index of @var{vector}.
+@deffn {Scheme Procedure} vector-ref vec k
+@deffnx {C Function} scm_vector_ref (vec, k)
+Return the contents of position @var{k} of @var{vec}.
+@var{k} must be a valid index of @var{vec}.
 @lisp
 (vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8
 (vector-ref '#(1 1 2 3 5 8 13 21)
@@ -770,9 +805,9 @@ Return the contents of position @var{k} of @var{vector}.
 @end lisp
 @end deffn
 
-@deftypefn {C Function} SCM scm_c_vector_ref (SCM v, size_t k)
+@deftypefn {C Function} SCM scm_c_vector_ref (SCM vec, size_t k)
 Return the contents of position @var{k} (a @code{size_t}) of
-@var{vector}.
+@var{vec}.
 @end deftypefn
 
 A vector created by one of the dynamic vector constructor procedures
@@ -785,10 +820,10 @@ considered as constants.  Currently, however, Guile does not detect this
 error.
 
 @rnindex vector-set!
-@deffn {Scheme Procedure} vector-set! vector k obj
-@deffnx {C Function} scm_vector_set_x vector k obj
-Store @var{obj} in position @var{k} of @var{vector}.
-@var{k} must be a valid index of @var{vector}.
+@deffn {Scheme Procedure} vector-set! vec k obj
+@deffnx {C Function} scm_vector_set_x (vec, k, obj)
+Store @var{obj} in position @var{k} of @var{vec}.
+@var{k} must be a valid index of @var{vec}.
 The value returned by @samp{vector-set!} is unspecified.
 @lisp
 (let ((vec (vector 0 '(2 2 2 2) "Anna")))
@@ -797,17 +832,22 @@ The value returned by @samp{vector-set!} is unspecified.
 @end lisp
 @end deffn
 
-@deftypefn {C Function} void scm_c_vector_set_x (SCM v, size_t k, SCM obj)
-Store @var{obj} in position @var{k} (a @code{size_t}) of @var{v}.
+@deftypefn {C Function} void scm_c_vector_set_x (SCM vec, size_t k, SCM obj)
+Store @var{obj} in position @var{k} (a @code{size_t}) of @var{vec}.
 @end deftypefn
 
 @rnindex vector-fill!
-@deffn {Scheme Procedure} vector-fill! v fill
-@deffnx {C Function} scm_vector_fill_x (v, fill)
-Store @var{fill} in every position of @var{vector}.  The value
+@deffn {Scheme Procedure} vector-fill! vec fill
+@deffnx {C Function} scm_vector_fill_x (vec, fill)
+Store @var{fill} in every position of @var{vec}.  The value
 returned by @code{vector-fill!} is unspecified.
 @end deffn
 
+@deffn {Scheme Procedure} vector-copy vec
+@deffnx {C Function} scm_vector_copy (vec)
+Return a copy of @var{vec}.
+@end deffn
+
 @deffn {Scheme Procedure} vector-move-left! vec1 start1 end1 vec2 start2
 @deffnx {C Function} scm_vector_move_left_x (vec1, start1, end1, vec2, start2)
 Copy elements from @var{vec1}, positions @var{start1} to @var{end1},
@@ -867,24 +907,27 @@ Evaluates to the element at position @var{idx} in the simple vector
 @var{vec}.  No type or range checking is done.
 @end deftypefn
 
-@deftypefn {C Macro} void SCM_SIMPLE_VECTOR_SET_X (SCM vec, size_t idx, SCM val)
+@deftypefn {C Macro} void SCM_SIMPLE_VECTOR_SET (SCM vec, size_t idx, SCM val)
 Sets the element at position @var{idx} in the simple vector
 @var{vec} to @var{val}.  No type or range checking is done.
 @end deftypefn
 
-@deftypefn {C Function} {const SCM} *scm_vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-Acquire a handle for the vector @var{vec} and return a pointer to the
+@deftypefn {C Function} {const SCM *} scm_vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
+Acquire a handle for the vector @var{vec} and return a pointer to the
 elements of it.  This pointer can only be used to read the elements of
 @var{vec}.  When @var{vec} is not a vector, an error is signaled.  The
-handle mustr eventually be released with
+handle must eventually be released with
 @code{scm_array_handle_release}.
 
 The variables pointed to by @var{lenp} and @var{incp} are filled with
-the number of elements of the vector and the increment between elements,
-respectively.  Note that the increment can well be negative.
+the number of elements of the vector and the increment (number of
+elements) between successive elements, respectively.  Successive
+elements of @var{vec} need not be contiguous in their underlying
+``root vector'' returned here; hence the increment is not necessarily
+equal to 1 and may well be negative too (@pxref{Shared Arrays}).
 
 The following example shows the typical way to use this function.  It
-creates a list of all elements of @code{vec} (in reverse order).
+creates a list of all elements of @var{vec} (in reverse order).
 
 @example
 scm_t_array_handle handle;
@@ -902,7 +945,7 @@ scm_array_handle_release (&handle);
 
 @end deftypefn
 
-@deftypefn {C Function} SCM *scm_vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
+@deftypefn {C Function} {SCM *} scm_vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
 Like @code{scm_vector_elements} but the pointer can be used to modify
 the vector.
 
@@ -915,7 +958,7 @@ size_t i, len;
 ssize_t inc;
 SCM *elt;
 
-elt = scm_vector_elements (vec, &handle, &len, &inc);
+elt = scm_vector_writable_elements (vec, &handle, &len, &inc);
 for (i = 0; i < len; i++, elt += inc)
   *elt = SCM_BOOL_T;
 scm_array_handle_release (&handle);
@@ -924,449 +967,17 @@ scm_array_handle_release (&handle);
 @end deftypefn
 
 @node Uniform Numeric Vectors
-@subsection Uniform Numeric Vectors
+@subsubsection Uniform Numeric Vectors
 
 A uniform numeric vector is a vector whose elements are all of a single
 numeric type.  Guile offers uniform numeric vectors for signed and
 unsigned 8-bit, 16-bit, 32-bit, and 64-bit integers, two sizes of
 floating point values, and complex floating-point numbers of these two
-sizes.
-
-Strings could be regarded as uniform vectors of characters,
-@xref{Strings}.  Likewise, bit vectors could be regarded as uniform
-vectors of bits, @xref{Bit Vectors}.  Both are sufficiently different
-from uniform numeric vectors that the procedures described here do not
-apply to these two data types.  However, both strings and bit vectors
-are generalized vectors, @xref{Generalized Vectors}, and arrays,
-@xref{Arrays}.
-
-Uniform numeric vectors are the special case of one dimensional uniform
-numeric arrays.
-
-Uniform numeric vectors can be useful since they consume less memory
-than the non-uniform, general vectors.  Also, since the types they can
-store correspond directly to C types, it is easier to work with them
-efficiently on a low level.  Consider image processing as an example,
-where you want to apply a filter to some image.  While you could store
-the pixels of an image in a general vector and write a general
-convolution function, things are much more efficient with uniform
-vectors: the convolution function knows that all pixels are unsigned
-8-bit values (say), and can use a very tight inner loop.
-
-That is, when it is written in C.  Functions for efficiently working
-with uniform numeric vectors from C are listed at the end of this
-section.
-
-Procedures similar to the vector procedures (@pxref{Vectors}) are
-provided for handling these uniform vectors, but they are distinct
-datatypes and the two cannot be inter-mixed.  If you want to work
-primarily with uniform numeric vectors, but want to offer support for
-general vectors as a convenience, you can use one of the
-@code{scm_any_to_*} functions.  They will coerce lists and vectors to
-the given type of uniform vector.  Alternatively, you can write two
-versions of your code: one that is fast and works only with uniform
-numeric vectors, and one that works with any kind of vector but is
-slower.
-
-One set of the procedures listed below is a generic one: it works with
-all types of uniform numeric vectors.  In addition to that, there is a
-set of procedures for each type that only works with that type.  Unless
-you really need to the generality of the first set, it is best to use
-the more specific functions.  They might not be that much faster, but
-their use can serve as a kind of declaration and makes it easier to
-optimize later on.
-
-The generic set of procedures uses @code{uniform} in its names, the
-specific ones use the tag from the following table.
-
-@table @nicode
-@item u8
-unsigned 8-bit integers
-
-@item s8
-signed 8-bit integers
-
-@item u16
-unsigned 16-bit integers
-
-@item s16
-signed 16-bit integers
-
-@item u32
-unsigned 32-bit integers
-
-@item s32
-signed 32-bit integers
-
-@item u64
-unsigned 64-bit integers
-
-@item s64
-signed 64-bit integers
-
-@item f32
-the C type @code{float}
-
-@item f64
-the C type @code{double}
-
-@item c32
-complex numbers in rectangular form with the real and imaginary part
-being a @code{float}
-
-@item c64
-complex numbers in rectangular form with the real and imaginary part
-being a @code{double}
-
-@end table
-
-The external representation (ie.@: read syntax) for these vectors is
-similar to normal Scheme vectors, but with an additional tag from the
-tabel above indiciating the vector's type.  For example,
-
-@lisp
-#u16(1 2 3)
-#f64(3.1415 2.71)
-@end lisp
-
-Note that the read syntax for floating-point here conflicts with
-@code{#f} for false.  In Standard Scheme one can write @code{(1 #f3)}
-for a three element list @code{(1 #f 3)}, but for Guile @code{(1 #f3)}
-is invalid.  @code{(1 #f 3)} is almost certainly what one should write
-anyway to make the intention clear, so this is rarely a problem.
-
-@deffn  {Scheme Procedure} uniform-vector? obj
-@deffnx {Scheme Procedure} u8vector? obj
-@deffnx {Scheme Procedure} s8vector? obj
-@deffnx {Scheme Procedure} u16vector? obj
-@deffnx {Scheme Procedure} s16vector? obj
-@deffnx {Scheme Procedure} u32vector? obj
-@deffnx {Scheme Procedure} s32vector? obj
-@deffnx {Scheme Procedure} u64vector? obj
-@deffnx {Scheme Procedure} s64vector? obj
-@deffnx {Scheme Procedure} f32vector? obj
-@deffnx {Scheme Procedure} f64vector? obj
-@deffnx {Scheme Procedure} c32vector? obj
-@deffnx {Scheme Procedure} c64vector? obj
-@deffnx {C Function} scm_uniform_vector_p obj
-@deffnx {C Function} scm_u8vector_p obj
-@deffnx {C Function} scm_s8vector_p obj
-@deffnx {C Function} scm_u16vector_p obj
-@deffnx {C Function} scm_s16vector_p obj
-@deffnx {C Function} scm_u32vector_p obj
-@deffnx {C Function} scm_s32vector_p obj
-@deffnx {C Function} scm_u64vector_p obj
-@deffnx {C Function} scm_s64vector_p obj
-@deffnx {C Function} scm_f32vector_p obj
-@deffnx {C Function} scm_f64vector_p obj
-@deffnx {C Function} scm_c32vector_p obj
-@deffnx {C Function} scm_c64vector_p obj
-Return @code{#t} if @var{obj} is a homogeneous numeric vector of the
-indicated type.
-@end deffn
-
-@deffn  {Scheme Procedure} make-u8vector n [value]
-@deffnx {Scheme Procedure} make-s8vector n [value]
-@deffnx {Scheme Procedure} make-u16vector n [value]
-@deffnx {Scheme Procedure} make-s16vector n [value]
-@deffnx {Scheme Procedure} make-u32vector n [value]
-@deffnx {Scheme Procedure} make-s32vector n [value]
-@deffnx {Scheme Procedure} make-u64vector n [value]
-@deffnx {Scheme Procedure} make-s64vector n [value]
-@deffnx {Scheme Procedure} make-f32vector n [value]
-@deffnx {Scheme Procedure} make-f64vector n [value]
-@deffnx {Scheme Procedure} make-c32vector n [value]
-@deffnx {Scheme Procedure} make-c64vector n [value]
-@deffnx {C Function} scm_make_u8vector n [value]
-@deffnx {C Function} scm_make_s8vector n [value]
-@deffnx {C Function} scm_make_u16vector n [value]
-@deffnx {C Function} scm_make_s16vector n [value]
-@deffnx {C Function} scm_make_u32vector n [value]
-@deffnx {C Function} scm_make_s32vector n [value]
-@deffnx {C Function} scm_make_u64vector n [value]
-@deffnx {C Function} scm_make_s64vector n [value]
-@deffnx {C Function} scm_make_f32vector n [value]
-@deffnx {C Function} scm_make_f64vector n [value]
-@deffnx {C Function} scm_make_c32vector n [value]
-@deffnx {C Function} scm_make_c64vector n [value]
-Return a newly allocated homogeneous numeric vector holding @var{n}
-elements of the indicated type.  If @var{value} is given, the vector
-is initialized with that value, otherwise the contents are
-unspecified.
-@end deffn
-
-@deffn  {Scheme Procedure} u8vector value @dots{}
-@deffnx {Scheme Procedure} s8vector value @dots{}
-@deffnx {Scheme Procedure} u16vector value @dots{}
-@deffnx {Scheme Procedure} s16vector value @dots{}
-@deffnx {Scheme Procedure} u32vector value @dots{}
-@deffnx {Scheme Procedure} s32vector value @dots{}
-@deffnx {Scheme Procedure} u64vector value @dots{}
-@deffnx {Scheme Procedure} s64vector value @dots{}
-@deffnx {Scheme Procedure} f32vector value @dots{}
-@deffnx {Scheme Procedure} f64vector value @dots{}
-@deffnx {Scheme Procedure} c32vector value @dots{}
-@deffnx {Scheme Procedure} c64vector value @dots{}
-@deffnx {C Function} scm_u8vector values
-@deffnx {C Function} scm_s8vector values
-@deffnx {C Function} scm_u16vector values
-@deffnx {C Function} scm_s16vector values
-@deffnx {C Function} scm_u32vector values
-@deffnx {C Function} scm_s32vector values
-@deffnx {C Function} scm_u64vector values
-@deffnx {C Function} scm_s64vector values
-@deffnx {C Function} scm_f32vector values
-@deffnx {C Function} scm_f64vector values
-@deffnx {C Function} scm_c32vector values
-@deffnx {C Function} scm_c64vector values
-Return a newly allocated homogeneous numeric vector of the indicated
-type, holding the given parameter @var{value}s.  The vector length is
-the number of parameters given.
-@end deffn
-
-@deffn  {Scheme Procedure} uniform-vector-length vec
-@deffnx {Scheme Procedure} u8vector-length vec
-@deffnx {Scheme Procedure} s8vector-length vec
-@deffnx {Scheme Procedure} u16vector-length vec
-@deffnx {Scheme Procedure} s16vector-length vec
-@deffnx {Scheme Procedure} u32vector-length vec
-@deffnx {Scheme Procedure} s32vector-length vec
-@deffnx {Scheme Procedure} u64vector-length vec
-@deffnx {Scheme Procedure} s64vector-length vec
-@deffnx {Scheme Procedure} f32vector-length vec
-@deffnx {Scheme Procedure} f64vector-length vec
-@deffnx {Scheme Procedure} c32vector-length vec
-@deffnx {Scheme Procedure} c64vector-length vec
-@deffnx {C Function} scm_uniform_vector_length vec
-@deffnx {C Function} scm_u8vector_length vec
-@deffnx {C Function} scm_s8vector_length vec
-@deffnx {C Function} scm_u16vector_length vec
-@deffnx {C Function} scm_s16vector_length vec
-@deffnx {C Function} scm_u32vector_length vec
-@deffnx {C Function} scm_s32vector_length vec
-@deffnx {C Function} scm_u64vector_length vec
-@deffnx {C Function} scm_s64vector_length vec
-@deffnx {C Function} scm_f32vector_length vec
-@deffnx {C Function} scm_f64vector_length vec
-@deffnx {C Function} scm_c32vector_length vec
-@deffnx {C Function} scm_c64vector_length vec
-Return the number of elements in @var{vec}.
-@end deffn
-
-@deffn  {Scheme Procedure} uniform-vector-ref vec i
-@deffnx {Scheme Procedure} u8vector-ref vec i
-@deffnx {Scheme Procedure} s8vector-ref vec i
-@deffnx {Scheme Procedure} u16vector-ref vec i
-@deffnx {Scheme Procedure} s16vector-ref vec i
-@deffnx {Scheme Procedure} u32vector-ref vec i
-@deffnx {Scheme Procedure} s32vector-ref vec i
-@deffnx {Scheme Procedure} u64vector-ref vec i
-@deffnx {Scheme Procedure} s64vector-ref vec i
-@deffnx {Scheme Procedure} f32vector-ref vec i
-@deffnx {Scheme Procedure} f64vector-ref vec i
-@deffnx {Scheme Procedure} c32vector-ref vec i
-@deffnx {Scheme Procedure} c64vector-ref vec i
-@deffnx {C Function} scm_uniform_vector_ref vec i
-@deffnx {C Function} scm_u8vector_ref vec i
-@deffnx {C Function} scm_s8vector_ref vec i
-@deffnx {C Function} scm_u16vector_ref vec i
-@deffnx {C Function} scm_s16vector_ref vec i
-@deffnx {C Function} scm_u32vector_ref vec i
-@deffnx {C Function} scm_s32vector_ref vec i
-@deffnx {C Function} scm_u64vector_ref vec i
-@deffnx {C Function} scm_s64vector_ref vec i
-@deffnx {C Function} scm_f32vector_ref vec i
-@deffnx {C Function} scm_f64vector_ref vec i
-@deffnx {C Function} scm_c32vector_ref vec i
-@deffnx {C Function} scm_c64vector_ref vec i
-Return the element at index @var{i} in @var{vec}.  The first element
-in @var{vec} is index 0.
-@end deffn
-
-@deffn  {Scheme Procedure} uniform-vector-set! vec i value
-@deffnx {Scheme Procedure} u8vector-set! vec i value
-@deffnx {Scheme Procedure} s8vector-set! vec i value
-@deffnx {Scheme Procedure} u16vector-set! vec i value
-@deffnx {Scheme Procedure} s16vector-set! vec i value
-@deffnx {Scheme Procedure} u32vector-set! vec i value
-@deffnx {Scheme Procedure} s32vector-set! vec i value
-@deffnx {Scheme Procedure} u64vector-set! vec i value
-@deffnx {Scheme Procedure} s64vector-set! vec i value
-@deffnx {Scheme Procedure} f32vector-set! vec i value
-@deffnx {Scheme Procedure} f64vector-set! vec i value
-@deffnx {Scheme Procedure} c32vector-set! vec i value
-@deffnx {Scheme Procedure} c64vector-set! vec i value
-@deffnx {C Function} scm_uniform_vector_set_x vec i value
-@deffnx {C Function} scm_u8vector_set_x vec i value
-@deffnx {C Function} scm_s8vector_set_x vec i value
-@deffnx {C Function} scm_u16vector_set_x vec i value
-@deffnx {C Function} scm_s16vector_set_x vec i value
-@deffnx {C Function} scm_u32vector_set_x vec i value
-@deffnx {C Function} scm_s32vector_set_x vec i value
-@deffnx {C Function} scm_u64vector_set_x vec i value
-@deffnx {C Function} scm_s64vector_set_x vec i value
-@deffnx {C Function} scm_f32vector_set_x vec i value
-@deffnx {C Function} scm_f64vector_set_x vec i value
-@deffnx {C Function} scm_c32vector_set_x vec i value
-@deffnx {C Function} scm_c64vector_set_x vec i value
-Set the element at index @var{i} in @var{vec} to @var{value}.  The
-first element in @var{vec} is index 0.  The return value is
-unspecified.
-@end deffn
-
-@deffn  {Scheme Procedure} uniform-vector->list vec
-@deffnx {Scheme Procedure} u8vector->list vec
-@deffnx {Scheme Procedure} s8vector->list vec
-@deffnx {Scheme Procedure} u16vector->list vec
-@deffnx {Scheme Procedure} s16vector->list vec
-@deffnx {Scheme Procedure} u32vector->list vec
-@deffnx {Scheme Procedure} s32vector->list vec
-@deffnx {Scheme Procedure} u64vector->list vec
-@deffnx {Scheme Procedure} s64vector->list vec
-@deffnx {Scheme Procedure} f32vector->list vec
-@deffnx {Scheme Procedure} f64vector->list vec
-@deffnx {Scheme Procedure} c32vector->list vec
-@deffnx {Scheme Procedure} c64vector->list vec
-@deffnx {C Function} scm_uniform_vector_to_list vec
-@deffnx {C Function} scm_u8vector_to_list vec
-@deffnx {C Function} scm_s8vector_to_list vec
-@deffnx {C Function} scm_u16vector_to_list vec
-@deffnx {C Function} scm_s16vector_to_list vec
-@deffnx {C Function} scm_u32vector_to_list vec
-@deffnx {C Function} scm_s32vector_to_list vec
-@deffnx {C Function} scm_u64vector_to_list vec
-@deffnx {C Function} scm_s64vector_to_list vec
-@deffnx {C Function} scm_f32vector_to_list vec
-@deffnx {C Function} scm_f64vector_to_list vec
-@deffnx {C Function} scm_c32vector_to_list vec
-@deffnx {C Function} scm_c64vector_to_list vec
-Return a newly allocated list holding all elements of @var{vec}.
-@end deffn
-
-@deffn  {Scheme Procedure} list->u8vector lst
-@deffnx {Scheme Procedure} list->s8vector lst
-@deffnx {Scheme Procedure} list->u16vector lst
-@deffnx {Scheme Procedure} list->s16vector lst
-@deffnx {Scheme Procedure} list->u32vector lst
-@deffnx {Scheme Procedure} list->s32vector lst
-@deffnx {Scheme Procedure} list->u64vector lst
-@deffnx {Scheme Procedure} list->s64vector lst
-@deffnx {Scheme Procedure} list->f32vector lst
-@deffnx {Scheme Procedure} list->f64vector lst
-@deffnx {Scheme Procedure} list->c32vector lst
-@deffnx {Scheme Procedure} list->c64vector lst
-@deffnx {C Function} scm_list_to_u8vector lst
-@deffnx {C Function} scm_list_to_s8vector lst
-@deffnx {C Function} scm_list_to_u16vector lst
-@deffnx {C Function} scm_list_to_s16vector lst
-@deffnx {C Function} scm_list_to_u32vector lst
-@deffnx {C Function} scm_list_to_s32vector lst
-@deffnx {C Function} scm_list_to_u64vector lst
-@deffnx {C Function} scm_list_to_s64vector lst
-@deffnx {C Function} scm_list_to_f32vector lst
-@deffnx {C Function} scm_list_to_f64vector lst
-@deffnx {C Function} scm_list_to_c32vector lst
-@deffnx {C Function} scm_list_to_c64vector lst
-Return a newly allocated homogeneous numeric vector of the indicated type,
-initialized with the elements of the list @var{lst}.
-@end deffn
-
-@deffn  {Scheme Procedure} any->u8vector obj
-@deffnx {Scheme Procedure} any->s8vector obj
-@deffnx {Scheme Procedure} any->u16vector obj
-@deffnx {Scheme Procedure} any->s16vector obj
-@deffnx {Scheme Procedure} any->u32vector obj
-@deffnx {Scheme Procedure} any->s32vector obj
-@deffnx {Scheme Procedure} any->u64vector obj
-@deffnx {Scheme Procedure} any->s64vector obj
-@deffnx {Scheme Procedure} any->f32vector obj
-@deffnx {Scheme Procedure} any->f64vector obj
-@deffnx {Scheme Procedure} any->c32vector obj
-@deffnx {Scheme Procedure} any->c64vector obj
-@deffnx {C Function} scm_any_to_u8vector obj
-@deffnx {C Function} scm_any_to_s8vector obj
-@deffnx {C Function} scm_any_to_u16vector obj
-@deffnx {C Function} scm_any_to_s16vector obj
-@deffnx {C Function} scm_any_to_u32vector obj
-@deffnx {C Function} scm_any_to_s32vector obj
-@deffnx {C Function} scm_any_to_u64vector obj
-@deffnx {C Function} scm_any_to_s64vector obj
-@deffnx {C Function} scm_any_to_f32vector obj
-@deffnx {C Function} scm_any_to_f64vector obj
-@deffnx {C Function} scm_any_to_c32vector obj
-@deffnx {C Function} scm_any_to_c64vector obj
-Return a (maybe newly allocated) uniform numeric vector of the indicated
-type, initialized with the elements of @var{obj}, which must be a list,
-a vector, or a uniform vector.  When @var{obj} is already a suitable
-uniform numeric vector, it is returned unchanged.
-@end deffn
-
-@deftypefn {C Function} int scm_is_uniform_vector (SCM uvec)
-Return non-zero when @var{uvec} is a uniform numeric vector, zero
-otherwise.
-@end deftypefn
-
-@deftypefn  {C Function} SCM scm_take_u8vector (const scm_t_uint8 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_s8vector (const scm_t_int8 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_u16vector (const scm_t_uint16 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_s168vector (const scm_t_int16 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_u32vector (const scm_t_uint32 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_s328vector (const scm_t_int32 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_u64vector (const scm_t_uint64 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_s64vector (const scm_t_int64 *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_f32vector (const float *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_f64vector (const double *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_c32vector (const float *data, size_t len)
-@deftypefnx {C Function} SCM scm_take_c64vector (const double *data, size_t len)
-Return a new uniform numeric vector of the indicated type and length
-that uses the memory pointed to by @var{data} to store its elements.
-This memory will eventually be freed with @code{free}.  The argument
-@var{len} specifies the number of elements in @var{data}, not its size
-in bytes.
-
-The @code{c32} and @code{c64} variants take a pointer to a C array of
-@code{float}s or @code{double}s.  The real parts of the complex numbers
-are at even indices in that array, the corresponding imaginary parts are
-at the following odd index.
-@end deftypefn
-
-@deftypefn {C Function} size_t scm_c_uniform_vector_length (SCM uvec)
-Return the number of elements of @var{uvec} as a @code{size_t}.
-@end deftypefn
-
-@deftypefn  {C Function} {const void} *scm_uniform_vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_uint8} *scm_u8vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_int8} *scm_s8vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_uint16} *scm_u16vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_int16} *scm_s16vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_uint32} *scm_u32vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_int32} *scm_s32vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_uint64} *scm_u64vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const scm_t_int64} *scm_s64vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const float} *scm_f23vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const double} *scm_f64vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const float} *scm_c32vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} {const double} *scm_c64vector_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-Like @code{scm_vector_elements} (which see), but returns a pointer to
-the elements of a uniform numeric vector of the indicated kind.
-@end deftypefn
+sizes. @xref{SRFI-4}, for more information.
 
-@deftypefn  {C Function} void *scm_uniform_vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_uint8 *scm_u8vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_int8 *scm_s8vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_uint16 *scm_u16vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_int16 *scm_s16vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_uint32 *scm_u32vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_int32 *scm_s32vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_uint64 *scm_u64vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} scm_t_int64 *scm_s64vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} float *scm_f23vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} double *scm_f64vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} float *scm_c32vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-@deftypefnx {C Function} double *scm_c64vector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *lenp, ssize_t *incp)
-Like @code{scm_vector_writable_elements} (which see), but returns a
-pointer to the elements of a uniform numeric vector of the indicated kind.
-@end deftypefn
+For many purposes, bytevectors work just as well as uniform vectors, and have
+the advantage that they integrate well with binary input and output.
+@xref{Bytevectors}, for more information on bytevectors.
 
 @node Bit Vectors
 @subsection Bit Vectors
@@ -1381,9 +992,8 @@ are displayed as a sequence of @code{0}s and @code{1}s prefixed by
 #*00000000
 @end example
 
-Bit vectors are are also generalized vectors, @xref{Generalized
-Vectors}, and can thus be used with the array procedures, @xref{Arrays}.
-Bit vectors are the special case of one dimensional bit arrays.
+Bit vectors are the special case of one dimensional bit arrays, and can
+thus be used with the array procedures, @xref{Arrays}.
 
 @deffn {Scheme Procedure} bitvector? obj
 @deffnx {C Function} scm_bitvector_p (obj)
@@ -1406,7 +1016,7 @@ Like @code{scm_make_bitvector}, but the length is given as a
 @code{size_t}.
 @end deftypefn
 
-@deffn {Scheme Procedure} bitvector . bits
+@deffn {Scheme Procedure} bitvector bit @dots{}
 @deffnx {C Function} scm_bitvector (bits)
 Create a new bitvector with the arguments as elements.
 @end deffn
@@ -1427,7 +1037,7 @@ Return the element at index @var{idx} of the bitvector
 @var{vec}.
 @end deffn
 
-@deftypefn {C Function} SCM scm_c_bitvector_ref (SCM obj, size_t idx)
+@deftypefn {C Function} SCM scm_c_bitvector_ref (SCM vec, size_t idx)
 Return the element at index @var{idx} of the bitvector
 @var{vec}.
 @end deftypefn
@@ -1438,7 +1048,7 @@ Set the element at index @var{idx} of the bitvector
 @var{vec} when @var{val} is true, else clear it.
 @end deffn
 
-@deftypefn {C Function} SCM scm_c_bitvector_set_x (SCM obj, size_t idx, SCM val)
+@deftypefn {C Function} SCM scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
 Set the element at index @var{idx} of the bitvector
 @var{vec} when @var{val} is true, else clear it.
 @end deftypefn
@@ -1473,7 +1083,7 @@ Return a count of how many entries in @var{bitvector} are equal to
 
 @deffn {Scheme Procedure} bit-position bool bitvector start
 @deffnx {C Function} scm_bit_position (bool, bitvector, start)
-Return the index of the first occurrance of @var{bool} in
+Return the index of the first occurrence of @var{bool} in
 @var{bitvector}, starting from @var{start}.  If there is no @var{bool}
 entry between @var{start} and the end of @var{bitvector}, then return
 @code{#f}.  For example,
@@ -1538,87 +1148,19 @@ For example,
 @end example
 @end deffn
 
-@deftypefn {C Function} {const scm_t_uint32} *scm_bitvector_elements (SCM vec, scm_t_array_handle *handle, size_t *offp, size_t *lenp, ssize_t *incp)
-Like @code{scm_vector_elements} (which see), but for bitvectors.  The
-variable pointed to by @var{offp} is set to the value returned by
-@code{scm_array_handle_bit_elements_offset}.  See
-@code{scm_array_handle_bit_elements} for how to use the returned pointer
-and the offset.
+@deftypefn {C Function} {const scm_t_uint32 *} scm_bitvector_elements (SCM vec, scm_t_array_handle *handle, size_t *offp, size_t *lenp, ssize_t *incp)
+Like @code{scm_vector_elements} (@pxref{Vector Accessing from C}), but
+for bitvectors.  The variable pointed to by @var{offp} is set to the
+value returned by @code{scm_array_handle_bit_elements_offset}.  See
+@code{scm_array_handle_bit_elements} for how to use the returned
+pointer and the offset.
 @end deftypefn
 
-@deftypefn {C Function} scm_t_uint32 *scm_bitvector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *offp, size_t *lenp, ssize_t *incp)
+@deftypefn {C Function} {scm_t_uint32 *} scm_bitvector_writable_elements (SCM vec, scm_t_array_handle *handle, size_t *offp, size_t *lenp, ssize_t *incp)
 Like @code{scm_bitvector_elements}, but the pointer is good for reading
 and writing.
 @end deftypefn
 
-@node Generalized Vectors
-@subsection Generalized Vectors
-
-Guile has a number of data types that are generally vector-like:
-strings, uniform numeric vectors, bitvectors, and of course ordinary
-vectors of arbitrary Scheme values.  These types are disjoint: a
-Scheme value belongs to at most one of the four types listed above.
-
-If you want to gloss over this distinction and want to treat all four
-types with common code, you can use the procedures in this section.
-They work with the @emph{generalized vector} type, which is the union
-of the four vector-like types.
-
-@deffn {Scheme Procedure} generalized-vector? obj
-@deffnx {C Function} scm_generalized_vector_p (obj)
-Return @code{#t} if @var{obj} is a vector, string,
-bitvector, or uniform numeric vector.
-@end deffn
-
-@deffn {Scheme Procedure} generalized-vector-length v
-@deffnx {C Function} scm_generalized_vector_length (v)
-Return the length of the generalized vector @var{v}.
-@end deffn
-
-@deffn {Scheme Procedure} generalized-vector-ref v idx
-@deffnx {C Function} scm_generalized_vector_ref (v, idx)
-Return the element at index @var{idx} of the
-generalized vector @var{v}.
-@end deffn
-
-@deffn {Scheme Procedure} generalized-vector-set! v idx val
-@deffnx {C Function} scm_generalized_vector_set_x (v, idx, val)
-Set the element at index @var{idx} of the
-generalized vector @var{v} to @var{val}.
-@end deffn
-
-@deffn {Scheme Procedure} generalized-vector->list v
-@deffnx {C Function} scm_generalized_vector_to_list (v)
-Return a new list whose elements are the elements of the
-generalized vector @var{v}.
-@end deffn
-
-@deftypefn {C Function} int scm_is_generalized_vector (SCM obj)
-Return @code{1} if @var{obj} is a vector, string,
-bitvector, or uniform numeric vector; else return @code{0}.
-@end deftypefn
-
-@deftypefn {C Function} size_t scm_c_generalized_vector_length (SCM v)
-Return the length of the generalized vector @var{v}.
-@end deftypefn
-
-@deftypefn {C Function} SCM scm_c_generalized_vector_ref (SCM v, size_t idx)
-Return the element at index @var{idx} of the generalized vector @var{v}.
-@end deftypefn
-
-@deftypefn {C Function} void scm_c_generalized_vector_set_x (SCM v, size_t idx, SCM val)
-Set the element at index @var{idx} of the generalized vector @var{v}
-to @var{val}.
-@end deftypefn
-
-@deftypefn {C Function} void scm_generalized_vector_get_handle (SCM v, scm_t_array_handle *handle)
-Like @code{scm_array_get_handle} but an error is signalled when @var{v}
-is not of rank one.  You can use @code{scm_array_handle_ref} and
-@code{scm_array_handle_set} to read and write the elements of @var{v},
-or you can use functions like @code{scm_array_handle_<foo>_elements} to
-deal with specific types of vectors.
-@end deftypefn
-
 @node Arrays
 @subsection Arrays
 @tpindex Arrays
@@ -1627,13 +1169,13 @@ deal with specific types of vectors.
 number of dimensions.  Each cell can be accessed in constant time by
 supplying an index for each dimension.
 
-In the current implementation, an array uses a generalized vector for
-the actual storage of its elements.  Any kind of generalized vector
-will do, so you can have arrays of uniform numeric values, arrays of
-characters, arrays of bits, and of course, arrays of arbitrary Scheme
-values.  For example, arrays with an underlying @code{c64vector} might
-be nice for digital signal processing, while arrays made from a
-@code{u8vector} might be used to hold gray-scale images.
+In the current implementation, an array uses a vector of some kind for
+the actual storage of its elements.  Any kind of vector will do, so you
+can have arrays of uniform numeric values, arrays of characters, arrays
+of bits, and of course, arrays of arbitrary Scheme values.  For example,
+arrays with an underlying @code{c64vector} might be nice for digital
+signal processing, while arrays made from a @code{u8vector} might be
+used to hold gray-scale images.
 
 The number of dimensions of an array is called its @dfn{rank}.  Thus,
 a matrix is an array of rank 2, while a vector has rank 1.  When
@@ -1652,17 +1194,18 @@ indices of this element is the empty list.
 Arrays contain zero elements when one of their dimensions has a zero
 length.  These empty arrays maintain information about their shape: a
 matrix with zero columns and 3 rows is different from a matrix with 3
-columns and zero row, which again is different from a vector of zero
-length.
+columns and zero rows, which again is different from a vector of
+length zero.
 
-Generalized vectors, such as strings, uniform numeric vectors, bit
-vectors and ordinary vectors, are the special case of one dimensional
-arrays.
+The array procedures are all polymorphic, treating strings, uniform
+numeric vectors, bytevectors, bit vectors and ordinary vectors as one
+dimensional arrays.
 
 @menu
-* Array Syntax::
-* Array Procedures::
-* Accessing Arrays from C::    
+* Array Syntax::                
+* Array Procedures::            
+* Shared Arrays::               
+* Accessing Arrays from C::     
 @end menu
 
 @node Array Syntax
@@ -1682,7 +1225,7 @@ In more words, the array tag is of the form
 where @code{<rank>} is a positive integer in decimal giving the rank of
 the array.  It is omitted when the rank is 1 and the array is non-shared
 and has zero-origin (see below).  For shared arrays and for a non-zero
-origin, the rank is always printed even when it is 1 to dinstinguish
+origin, the rank is always printed even when it is 1 to distinguish
 them from ordinary vectors.
 
 The @code{<vectag>} part is the tag for a uniform numeric vector, like
@@ -1696,7 +1239,7 @@ all @code{<@@lower>} parts are omitted.
 
 The @code{<:len>} part is a @samp{:} character followed by an unsigned
 integer in decimal giving the length of a dimension.  Like for the lower
-bounds, there is one @code{<:len>} for ech dimension, and the
+bounds, there is one @code{<:len>} for each dimension, and the
 @code{<:len>} part always follows the @code{<@@lower>} part for a
 dimension.  Lengths are only then printed when they can't be deduced
 from the nested lists of elements of the array literal, which can happen
@@ -1727,11 +1270,11 @@ is a uniform u8 array of rank 1.
 is a uniform u8 array of rank 2 with index ranges 2..3 and 3..4.
 
 @item #2()
-is a two-dimensional array with index ranges 0..-1 and 0..-1, i.e. both
-dimensions have length zero.
+is a two-dimensional array with index ranges 0..-1 and 0..-1, i.e.@:
+both dimensions have length zero.
 
 @item #2:0:2()
-is a two-dimensional array with index ranges 0..-1 and 0..1, i.e. the
+is a two-dimensional array with index ranges 0..-1 and 0..1, i.e.@: the
 first dimension has length zero, but the second has length 2.
 
 @item #0(12)
@@ -1739,6 +1282,16 @@ is a rank-zero array with contents 12.
 
 @end table
 
+In addition, bytevectors are also arrays, but use a different syntax
+(@pxref{Bytevectors}):
+
+@table @code
+
+@item #vu8(1 2 3)
+is a 3-byte long bytevector, with contents 1, 2, 3.
+
+@end table
+
 @node Array Procedures
 @subsubsection Array Procedures
 
@@ -1797,7 +1350,7 @@ Equivalent to @code{(make-typed-array #t @var{fill} @var{bound} ...)}.
 Create and return an array that has as many dimensions as there are
 @var{bound}s and (maybe) fill it with @var{fill}.
 
-The underlaying storage vector is created according to @var{type},
+The underlying storage vector is created according to @var{type},
 which must be a symbol whose name is the `vectag' of the array as
 explained above, or @code{#t} for ordinary, non-specialized arrays.
 
@@ -1812,8 +1365,8 @@ stored in the variable @code{*unspecified*} so that for example
 @code{(make-typed-array 'u32 *unspecified* 4)} creates a uninitialized
 @code{u32} vector of length 4.
 
-Each @var{bound} may be a positive non-zero integer @var{N}, in which
-case the index for that dimension can range from 0 through @var{N-1}; or
+Each @var{bound} may be a positive non-zero integer @var{n}, in which
+case the index for that dimension can range from 0 through @var{n}-1; or
 an explicit index range specifier in the form @code{(LOWER UPPER)},
 where both @var{lower} and @var{upper} are integers, possibly less than
 zero, and possibly the same number (however, @var{lower} cannot be
@@ -1861,7 +1414,7 @@ Return @code{#t} if the given index would be acceptable to
 
 @example
 (define a (make-array #f '(1 2) '(3 4)))
-(array-in-bounds? a 2 3) @result{} #f
+(array-in-bounds? a 2 3) @result{} #t
 (array-in-bounds? a 0 0) @result{} #f
 @end example
 @end deffn
@@ -1878,96 +1431,10 @@ a @result{} #2((#f #f) (#f #t))
 @end example
 @end deffn
 
-@deffn {Scheme Procedure} make-shared-array oldarray mapfunc bound @dots{}
-@deffnx {C Function} scm_make_shared_array (oldarray, mapfunc, boundlist)
-@code{make-shared-array} can be used to create shared subarrays of other
-arrays.  The @var{mapper} is a function that translates coordinates in
-the new array into coordinates in the old array.  A @var{mapper} must be
-affine, and its range must stay within the bounds of the old array, but
-it can be otherwise arbitrary.  A simple example:
-
-@lisp
-(define fred (make-array #f 8 8))
-(define freds-diagonal
-  (make-shared-array fred (lambda (i) (list i i)) 8))
-(array-set! freds-diagonal 'foo 3)
-(array-ref fred 3 3) @result{} foo
-(define freds-center
-  (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))
-(array-ref freds-center 0 0) @result{} foo
-@end lisp
-@end deffn
-
-@deffn {Scheme Procedure} shared-array-increments array
-@deffnx {C Function} scm_shared_array_increments (array)
-For each dimension, return the distance between elements in the root vector.
-@end deffn
-
-@deffn {Scheme Procedure} shared-array-offset array
-@deffnx {C Function} scm_shared_array_offset (array)
-Return the root vector index of the first element in the array.
-@end deffn
-
-@deffn {Scheme Procedure} shared-array-root array
-@deffnx {C Function} scm_shared_array_root (array)
-Return the root vector of a shared array.
-@end deffn
-
-@deffn {Scheme Procedure} transpose-array array dim1 @dots{}
-@deffnx {C Function} scm_transpose_array (array, dimlist)
-Return an array sharing contents with @var{array}, but with
-dimensions arranged in a different order.  There must be one
-@var{dim} argument for each dimension of @var{array}.
-@var{dim1}, @var{dim2}, @dots{} should be integers between 0
-and the rank of the array to be returned.  Each integer in that
-range must appear at least once in the argument list.
-
-The values of @var{dim1}, @var{dim2}, @dots{} correspond to
-dimensions in the array to be returned, and their positions in the
-argument list to dimensions of @var{array}.  Several @var{dim}s
-may have the same value, in which case the returned array will
-have smaller rank than @var{array}.
-
-@lisp
-(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))
-(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)
-(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}
-                #2((a 4) (b 5) (c 6))
-@end lisp
-@end deffn
-
-@deffn {Scheme Procedure} enclose-array array dim1 @dots{}
-@deffnx {C Function} scm_enclose_array (array, dimlist)
-@var{dim1}, @var{dim2} @dots{} should be nonnegative integers less than
-the rank of @var{array}.  @code{enclose-array} returns an array
-resembling an array of shared arrays.  The dimensions of each shared
-array are the same as the @var{dim}th dimensions of the original array,
-the dimensions of the outer array are the same as those of the original
-array that did not match a @var{dim}.
-
-An enclosed array is not a general Scheme array.  Its elements may not
-be set using @code{array-set!}.  Two references to the same element of
-an enclosed array will be @code{equal?} but will not in general be
-@code{eq?}.  The value returned by @code{array-prototype} when given an
-enclosed array is unspecified.
-
-For example,
-
-@lisp
-(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1)
-@result{}
-#<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))>
-
-(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0)
-@result{}
-#<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))>
-@end lisp
-@end deffn
-
 @deffn {Scheme Procedure} array-shape array
 @deffnx {Scheme Procedure} array-dimensions array
 @deffnx {C Function} scm_array_dimensions (array)
-Return a list of the bounds for each dimenson of @var{array}.
+Return a list of the bounds for each dimension of @var{array}.
 
 @code{array-shape} gives @code{(@var{lower} @var{upper})} for each
 dimension.  @code{array-dimensions} instead returns just
@@ -1983,12 +1450,15 @@ For example,
 @end example
 @end deffn
 
-@deffn {Scheme Procedure} array-rank obj
-@deffnx {C Function} scm_array_rank (obj)
-Return the number of dimensions of an array @var{obj}, or if @var{obj}
-is not an array then return 0.
+@deffn {Scheme Procedure} array-rank array
+@deffnx {C Function} scm_array_rank (array)
+Return the rank of @var{array}.
 @end deffn
 
+@deftypefn {C Function} size_t scm_c_array_rank (SCM array)
+Return the rank of @var{array} as a @code{size_t}.
+@end deftypefn
+
 @deffn {Scheme Procedure} array->list array
 @deffnx {C Function} scm_array_to_list (array)
 Return a list consisting of all the elements, in order, of
@@ -2014,26 +1484,11 @@ is unspecified.
 @end deffn
 
 @c begin (texi-doc-string "guile" "array-equal?")
-@deffn {Scheme Procedure} array-equal? array1 array2 @dots{}
+@deffn {Scheme Procedure} array-equal? array @dots{}
 Return @code{#t} if all arguments are arrays with the same shape, the
 same type, and have corresponding elements which are either
 @code{equal?} or @code{array-equal?}.  This function differs from
-@code{equal?} in that a one dimensional shared array may be
-@var{array-equal?} but not @var{equal?} to a vector or uniform vector.
-@end deffn
-
-@deffn {Scheme Procedure} array-contents array [strict]
-@deffnx {C Function} scm_array_contents (array, strict)
-If @var{array} may be @dfn{unrolled} into a one dimensional shared array
-without changing their order (last subscript changing fastest), then
-@code{array-contents} returns that shared array, otherwise it returns
-@code{#f}.  All arrays made by @code{make-array} and
-@code{make-generalized-array} may be unrolled, some arrays made by
-@code{make-shared-array} may not be.
-
-If the optional argument @var{strict} is provided, a shared array will
-be returned only if its elements are stored internally contiguous in
-memory.
+@code{equal?} (@pxref{Equality}) in that all arguments must be arrays.
 @end deffn
 
 @c  FIXME: array-map! accepts no source arrays at all, and in that
@@ -2043,10 +1498,10 @@ memory.
 @c  FIXME: array-for-each doesn't say what happens if the sources have
 @c  different index ranges.  The code currently iterates over the
 @c  indices of the first and expects the others to cover those.  That
-@c  at least vaguely matches array-map!, but is is meant to be a
+@c  at least vaguely matches array-map!, but is it meant to be a
 @c  documented feature?
 
-@deffn {Scheme Procedure} array-map! dst proc src1 @dots{} srcN
+@deffn {Scheme Procedure} array-map! dst proc src @dots{}
 @deffnx {Scheme Procedure} array-map-in-order! dst proc src1 @dots{} srcN
 @deffnx {C Function} scm_array_map_x (dst, proc, srclist)
 Set each element of the @var{dst} array to values obtained from calls
@@ -2063,10 +1518,10 @@ range in @var{dst}.  This ensures all @var{dst} indices are valid in
 each @var{src}.
 @end deffn
 
-@deffn {Scheme Procedure} array-for-each proc src1 @dots{} srcN
+@deffn {Scheme Procedure} array-for-each proc src1 src2 @dots{}
 @deffnx {C Function} scm_array_for_each (proc, src1, srclist)
-Apply @var{proc} to each tuple of elements of @var{src1} @dots{}
-@var{srcN}, in row-major order.  The value returned is unspecified.
+Apply @var{proc} to each tuple of elements of @var{src1} @var{src2}
+@dots{}, in row-major order.  The value returned is unspecified.
 @end deffn
 
 @deffn {Scheme Procedure} array-index-map! dst proc
@@ -2108,10 +1563,10 @@ $\left(\matrix{%
 
 @deffn {Scheme Procedure} uniform-array-read! ra [port_or_fd [start [end]]]
 @deffnx {C Function} scm_uniform_array_read_x (ra, port_or_fd, start, end)
-Attempt to read all elements of @var{ura}, in lexicographic order, as
-binary objects from @var{port-or-fdes}.
+Attempt to read all elements of array @var{ra}, in lexicographic order, as
+binary objects from @var{port_or_fd}.
 If an end of file is encountered,
-the objects up to that point are put into @var{ura}
+the objects up to that point are put into @var{ra}
 (starting at the beginning) and the remainder of the array is
 unchanged.
 
@@ -2120,34 +1575,192 @@ a specified region of a vector (or linearized array) to be read,
 leaving the remainder of the vector unchanged.
 
 @code{uniform-array-read!} returns the number of objects read.
-@var{port-or-fdes} may be omitted, in which case it defaults to the value
+@var{port_or_fd} may be omitted, in which case it defaults to the value
 returned by @code{(current-input-port)}.
 @end deffn
 
-@deffn {Scheme Procedure} uniform-array-write v [port_or_fd [start [end]]]
-@deffnx {C Function} scm_uniform_array_write (v, port_or_fd, start, end)
-Writes all elements of @var{ura} as binary objects to
-@var{port-or-fdes}.
+@deffn {Scheme Procedure} uniform-array-write ra [port_or_fd [start [end]]]
+@deffnx {C Function} scm_uniform_array_write (ra, port_or_fd, start, end)
+Writes all elements of @var{ra} as binary objects to
+@var{port_or_fd}.
 
 The optional arguments @var{start}
 and @var{end} allow
 a specified region of a vector (or linearized array) to be written.
 
 The number of objects actually written is returned.
-@var{port-or-fdes} may be
+@var{port_or_fd} may be
 omitted, in which case it defaults to the value returned by
 @code{(current-output-port)}.
 @end deffn
 
+@node Shared Arrays
+@subsubsection Shared Arrays
+
+@deffn {Scheme Procedure} make-shared-array oldarray mapfunc bound @dots{}
+@deffnx {C Function} scm_make_shared_array (oldarray, mapfunc, boundlist)
+Return a new array which shares the storage of @var{oldarray}.
+Changes made through either affect the same underlying storage.  The
+@var{bound} @dots{} arguments are the shape of the new array, the same
+as @code{make-array} (@pxref{Array Procedures}).
+
+@var{mapfunc} translates coordinates from the new array to the
+@var{oldarray}.  It's called as @code{(@var{mapfunc} newidx1 @dots{})}
+with one parameter for each dimension of the new array, and should
+return a list of indices for @var{oldarray}, one for each dimension of
+@var{oldarray}.
+
+@var{mapfunc} must be affine linear, meaning that each @var{oldarray}
+index must be formed by adding integer multiples (possibly negative)
+of some or all of @var{newidx1} etc, plus a possible integer offset.
+The multiples and offset must be the same in each call.
+
+@sp 1
+One good use for a shared array is to restrict the range of some
+dimensions, so as to apply say @code{array-for-each} or
+@code{array-fill!} to only part of an array.  The plain @code{list}
+function can be used for @var{mapfunc} in this case, making no changes
+to the index values.  For example,
+
+@example
+(make-shared-array #2((a b c) (d e f) (g h i)) list 3 2)
+@result{} #2((a b) (d e) (g h))
+@end example
+
+The new array can have fewer dimensions than @var{oldarray}, for
+example to take a column from an array.
+
+@example
+(make-shared-array #2((a b c) (d e f) (g h i))
+                   (lambda (i) (list i 2))
+                   '(0 2))
+@result{} #1(c f i)
+@end example
+
+A diagonal can be taken by using the single new array index for both
+row and column in the old array.  For example,
+
+@example
+(make-shared-array #2((a b c) (d e f) (g h i))
+                   (lambda (i) (list i i))
+                   '(0 2))
+@result{} #1(a e i)
+@end example
+
+Dimensions can be increased by for instance considering portions of a
+one dimensional array as rows in a two dimensional array.
+(@code{array-contents} below can do the opposite, flattening an
+array.)
+
+@example
+(make-shared-array #1(a b c d e f g h i j k l)
+                   (lambda (i j) (list (+ (* i 3) j)))
+                   4 3)
+@result{} #2((a b c) (d e f) (g h i) (j k l))
+@end example
+
+By negating an index the order that elements appear can be reversed.
+The following just reverses the column order,
+
+@example
+(make-shared-array #2((a b c) (d e f) (g h i))
+                   (lambda (i j) (list i (- 2 j)))
+                   3 3)
+@result{} #2((c b a) (f e d) (i h g))
+@end example
+
+A fixed offset on indexes allows for instance a change from a 0 based
+to a 1 based array,
+
+@example
+(define x #2((a b c) (d e f) (g h i)))
+(define y (make-shared-array x
+                             (lambda (i j) (list (1- i) (1- j)))
+                             '(1 3) '(1 3)))
+(array-ref x 0 0) @result{} a
+(array-ref y 1 1) @result{} a
+@end example
+
+A multiple on an index allows every Nth element of an array to be
+taken.  The following is every third element,
+
+@example
+(make-shared-array #1(a b c d e f g h i j k l)
+                   (lambda (i) (list (* i 3)))
+                   4)
+@result{} #1(a d g j)
+@end example
+
+The above examples can be combined to make weird and wonderful
+selections from an array, but it's important to note that because
+@var{mapfunc} must be affine linear, arbitrary permutations are not
+possible.
+
+In the current implementation, @var{mapfunc} is not called for every
+access to the new array but only on some sample points to establish a
+base and stride for new array indices in @var{oldarray} data.  A few
+sample points are enough because @var{mapfunc} is linear.
+@end deffn
+
+@deffn {Scheme Procedure} shared-array-increments array
+@deffnx {C Function} scm_shared_array_increments (array)
+For each dimension, return the distance between elements in the root vector.
+@end deffn
+
+@deffn {Scheme Procedure} shared-array-offset array
+@deffnx {C Function} scm_shared_array_offset (array)
+Return the root vector index of the first element in the array.
+@end deffn
+
+@deffn {Scheme Procedure} shared-array-root array
+@deffnx {C Function} scm_shared_array_root (array)
+Return the root vector of a shared array.
+@end deffn
+
+@deffn {Scheme Procedure} array-contents array [strict]
+@deffnx {C Function} scm_array_contents (array, strict)
+If @var{array} may be @dfn{unrolled} into a one dimensional shared array
+without changing their order (last subscript changing fastest), then
+@code{array-contents} returns that shared array, otherwise it returns
+@code{#f}.  All arrays made by @code{make-array} and
+@code{make-typed-array} may be unrolled, some arrays made by
+@code{make-shared-array} may not be.
+
+If the optional argument @var{strict} is provided, a shared array will
+be returned only if its elements are stored internally contiguous in
+memory.
+@end deffn
+
+@deffn {Scheme Procedure} transpose-array array dim1 dim2 @dots{}
+@deffnx {C Function} scm_transpose_array (array, dimlist)
+Return an array sharing contents with @var{array}, but with
+dimensions arranged in a different order.  There must be one
+@var{dim} argument for each dimension of @var{array}.
+@var{dim1}, @var{dim2}, @dots{} should be integers between 0
+and the rank of the array to be returned.  Each integer in that
+range must appear at least once in the argument list.
+
+The values of @var{dim1}, @var{dim2}, @dots{} correspond to
+dimensions in the array to be returned, and their positions in the
+argument list to dimensions of @var{array}.  Several @var{dim}s
+may have the same value, in which case the returned array will
+have smaller rank than @var{array}.
+
+@lisp
+(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))
+(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)
+(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}
+                #2((a 4) (b 5) (c 6))
+@end lisp
+@end deffn
+
 @node Accessing Arrays from C
 @subsubsection Accessing Arrays from C
 
-Arrays, especially uniform numeric arrays, are useful to efficiently
-represent large amounts of rectangularily organized information, such as
-matrices, images, or generally blobs of binary data.  It is desirable to
-access these blobs in a C like manner so that they can be handed to
-external C code such as linear algebra libraries or image processing
-routines.
+For interworking with external C code, Guile provides an API to allow C
+code to access the elements of a Scheme array.  In particular, for
+uniform numeric arrays, the API exposes the underlying uniform data as a
+C array of numbers of the relevant type.
 
 While pointers to the elements of an array are in use, the array itself
 must be protected so that the pointer remains valid.  Such a protected
@@ -2160,21 +1773,14 @@ error is signalled.
 the danger of a deadlock.  In a multi-threaded program, you will need
 additional synchronization to avoid modifying reserved arrays.)
 
-You must take care to always unreserve an array after reserving it, also
-in the presence of non-local exits.  To simplify this, reserving and
-unreserving work like a frame (@pxref{Frames}): a call to
-@code{scm_array_get_handle} can be thought of as beginning a frame and
-@code{scm_array_handle_release} as ending it.  When a non-local exit
-happens between these two calls, the array is implicitely unreserved.
+You must take care to always unreserve an array after reserving it,
+even in the presence of non-local exits.  If a non-local exit can
+happen between these two calls, you should install a dynwind context
+that releases the array when it is left (@pxref{Dynamic Wind}).
 
-That is, you need to properly pair reserving and unreserving in your
-code, but you don't need to worry about non-local exits.
-
-These calls and other pairs of calls that establish dynamic contexts
-need to be properly nested.  If you begin a frame prior to reserving an
-array, you need to unreserve the array before ending the frame.
-Likewise, when reserving two or more arrays in a certain order, you need
-to unreserve them in the opposite order.
+In addition, array reserving and unreserving must be properly
+paired.  For instance, when reserving two or more arrays in a certain
+order, you need to unreserve them in the opposite order.
 
 Once you have reserved an array and have retrieved the pointer to its
 elements, you must figure out the layout of the elements in memory.
@@ -2190,11 +1796,11 @@ indices.  The scalar position then is the offset of the element with the
 given indices from the start of the storage block of the array.
 
 In Guile, this mapping function is restricted to be @dfn{affine}: all
-mapping function of Guile arrays can be written as @code{p = b +
+mapping functions of Guile arrays can be written as @code{p = b +
 c[0]*i[0] + c[1]*i[1] + ... + c[n-1]*i[n-1]} where @code{i[k]} is the
-@nicode{k}th index and @code{n} is the rank of the array.  For example,
-a matrix of size 3x3 would have @code{b == 0}, @code{c[0] == 3} and
-@code{c[1] == 1}.  When you transpose this matrix (with
+@nicode{k}th index and @code{n} is the rank of the array.  For
+example, a matrix of size 3x3 would have @code{b == 0}, @code{c[0] ==
+3} and @code{c[1] == 1}.  When you transpose this matrix (with
 @code{transpose-array}, say), you will get an array whose mapping
 function has @code{b == 0}, @code{c[0] == 1} and @code{c[1] == 3}.
 
@@ -2248,7 +1854,7 @@ that this can be negative.
 @end table
 @end deftp
 
-@deftypefn {C Function} {const scm_t_array_dim} *scm_array_handle_dims (scm_t_array_handle *handle)
+@deftypefn {C Function} {const scm_t_array_dim *} scm_array_handle_dims (scm_t_array_handle *handle)
 Return a pointer to a C vector of information about the dimensions of
 the array represented by @var{handle}.  This pointer is valid as long as
 the array remains reserved.  As explained above, the
@@ -2280,6 +1886,14 @@ for (i = 0; i < RANK; i++)
 @end example
 @end deftypefn
 
+@deftypefn {C Function} ssize_t scm_array_handle_pos (scm_t_array_handle *handle, SCM indices)
+Compute the position corresponding to @var{indices}, a list of
+indices.  The position is computed as described above for
+@code{scm_array_handle_dims}.  The number of the indices and their
+range is checked and an appropriate error is signalled for invalid
+indices.
+@end deftypefn
+
 @deftypefn {C Function} SCM scm_array_handle_ref (scm_t_array_handle *handle, ssize_t pos)
 Return the element at position @var{pos} in the storage block of the
 array represented by @var{handle}.  Any kind of array is acceptable.  No
@@ -2293,24 +1907,24 @@ acceptable.  No range checking is done on @var{pos}.  An error is
 signalled when the array can not store @var{val}.
 @end deftypefn
 
-@deftypefn {C Function} {const SCM} *scm_array_handle_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {const SCM *} scm_array_handle_elements (scm_t_array_handle *handle)
 Return a pointer to the elements of a ordinary array of general Scheme
 values (i.e., a non-uniform array) for reading.  This pointer is valid
 as long as the array remains reserved.
 @end deftypefn
 
-@deftypefn {C Function} SCM *scm_array_handle_writable_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {SCM *} scm_array_handle_writable_elements (scm_t_array_handle *handle)
 Like @code{scm_array_handle_elements}, but the pointer is good for
 reading and writing.
 @end deftypefn
 
-@deftypefn {C Function} {const void} *scm_array_handle_uniform_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {const void *} scm_array_handle_uniform_elements (scm_t_array_handle *handle)
 Return a pointer to the elements of a uniform numeric array for reading.
 This pointer is valid as long as the array remains reserved.  The size
 of each element is given by @code{scm_array_handle_uniform_element_size}.
 @end deftypefn
 
-@deftypefn {C Function} void *scm_array_handle_uniform_writable_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {void *} scm_array_handle_uniform_writable_elements (scm_t_array_handle *handle)
 Like @code{scm_array_handle_uniform_elements}, but the pointer is good
 reading and writing.
 @end deftypefn
@@ -2320,18 +1934,18 @@ Return the size of one element of the uniform numeric array represented
 by @var{handle}.
 @end deftypefn
 
-@deftypefn  {C Function} {const scm_t_uint8} *scm_array_handle_u8_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_int8} *scm_array_handle_s8_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_uint16} *scm_array_handle_u16_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_int16} *scm_array_handle_s16_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_uint32} *scm_array_handle_u32_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_int32} *scm_array_handle_s32_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_uint64} *scm_array_handle_u64_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const scm_t_int64} *scm_array_handle_s64_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const float} *scm_array_handle_f32_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const double} *scm_array_handle_f64_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const float} *scm_array_handle_c32_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} {const double} *scm_array_handle_c64_elements (scm_t_array_handle *handle)
+@deftypefn  {C Function} {const scm_t_uint8 *} scm_array_handle_u8_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_int8 *} scm_array_handle_s8_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_uint16 *} scm_array_handle_u16_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_int16 *} scm_array_handle_s16_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_uint32 *} scm_array_handle_u32_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_int32 *} scm_array_handle_s32_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_uint64 *} scm_array_handle_u64_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const scm_t_int64 *} scm_array_handle_s64_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const float *} scm_array_handle_f32_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const double *} scm_array_handle_f64_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const float *} scm_array_handle_c32_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {const double *} scm_array_handle_c64_elements (scm_t_array_handle *handle)
 Return a pointer to the elements of a uniform numeric array of the
 indicated kind for reading.  This pointer is valid as long as the array
 remains reserved.
@@ -2341,23 +1955,23 @@ to pairs of floating point numbers.  The even index holds the real part,
 the odd index the imaginary part of the complex number.
 @end deftypefn
 
-@deftypefn {C Function} scm_t_uint8 *scm_array_handle_u8_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_int8 *scm_array_handle_s8_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_uint16 *scm_array_handle_u16_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_int16 *scm_array_handle_s16_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_uint32 *scm_array_handle_u32_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_int32 *scm_array_handle_s32_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_uint64 *scm_array_handle_u64_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} scm_t_int64 *scm_array_handle_s64_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} float *scm_array_handle_f32_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} double *scm_array_handle_f64_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} float *scm_array_handle_c32_writable_elements (scm_t_array_handle *handle)
-@deftypefnx {C Function} double *scm_array_handle_c64_writable_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {scm_t_uint8 *} scm_array_handle_u8_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_int8 *} scm_array_handle_s8_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_uint16 *} scm_array_handle_u16_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_int16 *} scm_array_handle_s16_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_uint32 *} scm_array_handle_u32_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_int32 *} scm_array_handle_s32_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_uint64 *} scm_array_handle_u64_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {scm_t_int64 *} scm_array_handle_s64_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {float *} scm_array_handle_f32_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {double *} scm_array_handle_f64_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {float *} scm_array_handle_c32_writable_elements (scm_t_array_handle *handle)
+@deftypefnx {C Function} {double *} scm_array_handle_c64_writable_elements (scm_t_array_handle *handle)
 Like @code{scm_array_handle_<kind>_elements}, but the pointer is good
 for reading and writing.
 @end deftypefn
 
-@deftypefn {C Function} {const scm_t_uint32} *scm_array_handle_bit_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {const scm_t_uint32 *} scm_array_handle_bit_elements (scm_t_array_handle *handle)
 Return a pointer to the words that store the bits of the represented
 array, which must be a bit array.
 
@@ -2401,55 +2015,480 @@ scm_array_handle_release (&handle);
 
 @end deftypefn
 
-@deftypefn {C Function} scm_t_uint32 *scm_array_handle_bit_writable_elements (scm_t_array_handle *handle)
+@deftypefn {C Function} {scm_t_uint32 *} scm_array_handle_bit_writable_elements (scm_t_array_handle *handle)
 Like @code{scm_array_handle_bit_elements} but the pointer is good for
 reading and writing.  You must take care not to modify bits outside of
 the allowed index range of the array, even for contiguous arrays.
 @end deftypefn
 
-@node Records
-@subsection Records
+@node VLists
+@subsection VLists
 
-A @dfn{record type} is a first class object representing a user-defined
-data type.  A @dfn{record} is an instance of a record type.
+@cindex vlist
 
-@deffn {Scheme Procedure} record? obj
-Return @code{#t} if @var{obj} is a record of any type and @code{#f}
-otherwise.
+The @code{(ice-9 vlist)} module provides an implementation of the @dfn{VList}
+data structure designed by Phil Bagwell in 2002.  VLists are immutable lists,
+which can contain any Scheme object.  They improve on standard Scheme linked
+lists in several areas:
 
-Note that @code{record?} may be true of any Scheme value; there is no
-promise that records are disjoint with other Scheme types.
-@end deffn
+@itemize
+@item
+Random access has typically constant-time complexity.
 
-@deffn {Scheme Procedure} make-record-type type-name field-names
-Return a @dfn{record-type descriptor}, a value representing a new data
-type disjoint from all others.  The @var{type-name} argument must be a
-string, but is only used for debugging purposes (such as the printed
-representation of a record of the new type).  The @var{field-names}
-argument is a list of symbols naming the @dfn{fields} of a record of the
-new type.  It is an error if the list contains any duplicates.  It is
-unspecified how record-type descriptors are represented.
-@end deffn
+@item
+Computing the length of a VList has time complexity logarithmic in the number of
+elements.
 
-@deffn {Scheme Procedure} record-constructor rtd [field-names]
-Return a procedure for constructing new members of the type represented
-by @var{rtd}.  The returned procedure accepts exactly as many arguments
-as there are symbols in the given list, @var{field-names}; these are
-used, in order, as the initial values of those fields in a new record,
-which is returned by the constructor procedure.  The values of any
-fields not named in that list are unspecified.  The @var{field-names}
-argument defaults to the list of field names in the call to
-@code{make-record-type} that created the type represented by @var{rtd};
-if the @var{field-names} argument is provided, it is an error if it
-contains any duplicates or any symbols not in the default list.
-@end deffn
+@item
+VLists use less storage space than standard lists.
 
-@deffn {Scheme Procedure} record-predicate rtd
-Return a procedure for testing membership in the type represented by
-@var{rtd}.  The returned procedure accepts exactly one argument and
-returns a true value if the argument is a member of the indicated record
-type; it returns a false value otherwise.
-@end deffn
+@item
+VList elements are stored in contiguous regions, which improves memory locality
+and leads to more efficient use of hardware caches.
+@end itemize
+
+The idea behind VLists is to store vlist elements in increasingly large
+contiguous blocks (implemented as vectors here).  These blocks are linked to one
+another using a pointer to the next block and an offset within that block.  The
+size of these blocks form a geometric series with ratio
+@code{block-growth-factor} (2 by default).
+
+The VList structure also serves as the basis for the @dfn{VList-based hash
+lists} or ``vhashes'', an immutable dictionary type (@pxref{VHashes}).
+
+However, the current implementation in @code{(ice-9 vlist)} has several
+noteworthy shortcomings:
+
+@itemize
+
+@item
+It is @emph{not} thread-safe.  Although operations on vlists are all
+@dfn{referentially transparent} (i.e., purely functional), adding elements to a
+vlist with @code{vlist-cons} mutates part of its internal structure, which makes
+it non-thread-safe.  This could be fixed, but it would slow down
+@code{vlist-cons}.
+
+@item
+@code{vlist-cons} always allocates at least as much memory as @code{cons}.
+Again, Phil Bagwell describes how to fix it, but that would require tuning the
+garbage collector in a way that may not be generally beneficial.
+
+@item
+@code{vlist-cons} is a Scheme procedure compiled to bytecode, and it does not
+compete with the straightforward C implementation of @code{cons}, and with the
+fact that the VM has a special @code{cons} instruction.
+
+@end itemize
+
+We hope to address these in the future.
+
+The programming interface exported by @code{(ice-9 vlist)} is defined below.
+Most of it is the same as SRFI-1 with an added @code{vlist-} prefix to function
+names.
+
+@deffn {Scheme Procedure} vlist? obj
+Return true if @var{obj} is a VList.
+@end deffn
+
+@defvr {Scheme Variable} vlist-null
+The empty VList.  Note that it's possible to create an empty VList not
+@code{eq?} to @code{vlist-null}; thus, callers should always use
+@code{vlist-null?} when testing whether a VList is empty.
+@end defvr
+
+@deffn {Scheme Procedure} vlist-null? vlist
+Return true if @var{vlist} is empty.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-cons item vlist
+Return a new vlist with @var{item} as its head and @var{vlist} as its tail.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-head vlist
+Return the head of @var{vlist}.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-tail vlist
+Return the tail of @var{vlist}.
+@end deffn
+
+@defvr {Scheme Variable} block-growth-factor
+A fluid that defines the growth factor of VList blocks, 2 by default.
+@end defvr
+
+The functions below provide the usual set of higher-level list operations.
+
+@deffn {Scheme Procedure} vlist-fold proc init vlist
+@deffnx {Scheme Procedure} vlist-fold-right proc init vlist
+Fold over @var{vlist}, calling @var{proc} for each element, as for SRFI-1
+@code{fold} and @code{fold-right} (@pxref{SRFI-1, @code{fold}}).
+@end deffn
+
+@deffn {Scheme Procedure} vlist-ref vlist index
+Return the element at index @var{index} in @var{vlist}.  This is typically a
+constant-time operation.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-length vlist
+Return the length of @var{vlist}.  This is typically logarithmic in the number
+of elements in @var{vlist}.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-reverse vlist
+Return a new @var{vlist} whose content are those of @var{vlist} in reverse
+order.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-map proc vlist
+Map @var{proc} over the elements of @var{vlist} and return a new vlist.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-for-each proc vlist
+Call @var{proc} on each element of @var{vlist}.  The result is unspecified.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-drop vlist count
+Return a new vlist that does not contain the @var{count} first elements of
+@var{vlist}.  This is typically a constant-time operation.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-take vlist count
+Return a new vlist that contains only the @var{count} first elements of
+@var{vlist}.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-filter pred vlist
+Return a new vlist containing all the elements from @var{vlist} that satisfy
+@var{pred}.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-delete x vlist [equal?]
+Return a new vlist corresponding to @var{vlist} without the elements
+@var{equal?} to @var{x}.
+@end deffn
+
+@deffn {Scheme Procedure} vlist-unfold p f g seed [tail-gen]
+@deffnx {Scheme Procedure} vlist-unfold-right p f g seed [tail]
+Return a new vlist, as for SRFI-1 @code{unfold} and @code{unfold-right}
+(@pxref{SRFI-1, @code{unfold}}).
+@end deffn
+
+@deffn {Scheme Procedure} vlist-append vlist @dots{}
+Append the given vlists and return the resulting vlist.
+@end deffn
+
+@deffn {Scheme Procedure} list->vlist lst
+Return a new vlist whose contents correspond to @var{lst}.
+@end deffn
+
+@deffn {Scheme Procedure} vlist->list vlist
+Return a new list whose contents match those of @var{vlist}.
+@end deffn
+
+@node Record Overview
+@subsection Record Overview
+
+@cindex record
+@cindex structure
+
+@dfn{Records}, also called @dfn{structures}, are Scheme's primary
+mechanism to define new disjoint types.  A @dfn{record type} defines a
+list of @dfn{fields} that instances of the type consist of.  This is like
+C's @code{struct}.
+
+Historically, Guile has offered several different ways to define record
+types and to create records, offering different features, and making
+different trade-offs.  Over the years, each ``standard'' has also come
+with its own new record interface, leading to a maze of record APIs.
+
+At the highest level is SRFI-9, a high-level record interface
+implemented by most Scheme implementations (@pxref{SRFI-9}).  It defines
+a simple and efficient syntactic abstraction of record types and their
+associated type predicate, fields, and field accessors.  SRFI-9 is
+suitable for most uses, and this is the recommended way to create record
+types in Guile.  Similar high-level record APIs include SRFI-35
+(@pxref{SRFI-35}) and R6RS records (@pxref{rnrs records syntactic}).
+
+Then comes Guile's historical ``records'' API (@pxref{Records}).  Record
+types defined this way are first-class objects.  Introspection
+facilities are available, allowing users to query the list of fields or
+the value of a specific field at run-time, without prior knowledge of
+the type.
+
+Finally, the common denominator of these interfaces is Guile's
+@dfn{structure} API (@pxref{Structures}).  Guile's structures are the
+low-level building block for all other record APIs.  Application writers
+will normally not need to use it.
+
+Records created with these APIs may all be pattern-matched using Guile's
+standard pattern matcher (@pxref{Pattern Matching}).
+
+
+@node SRFI-9 Records
+@subsection SRFI-9 Records
+
+@cindex SRFI-9
+@cindex record
+
+SRFI-9 standardizes a syntax for defining new record types and creating
+predicate, constructor, and field getter and setter functions.  In Guile
+this is the recommended option to create new record types (@pxref{Record
+Overview}).  It can be used with:
+
+@example
+(use-modules (srfi srfi-9))
+@end example
+
+@deffn {library syntax} define-record-type type @* (constructor fieldname @dots{}) @* predicate @* (fieldname accessor [modifier]) @dots{}
+@sp 1
+Create a new record type, and make various @code{define}s for using
+it.  This syntax can only occur at the top-level, not nested within
+some other form.
+
+@var{type} is bound to the record type, which is as per the return
+from the core @code{make-record-type}.  @var{type} also provides the
+name for the record, as per @code{record-type-name}.
+
+@var{constructor} is bound to a function to be called as
+@code{(@var{constructor} fieldval @dots{})} to create a new record of
+this type.  The arguments are initial values for the fields, one
+argument for each field, in the order they appear in the
+@code{define-record-type} form.
+
+The @var{fieldname}s provide the names for the record fields, as per
+the core @code{record-type-fields} etc, and are referred to in the
+subsequent accessor/modifier forms.
+
+@var{predicate} is bound to a function to be called as
+@code{(@var{predicate} obj)}.  It returns @code{#t} or @code{#f}
+according to whether @var{obj} is a record of this type.
+
+Each @var{accessor} is bound to a function to be called
+@code{(@var{accessor} record)} to retrieve the respective field from a
+@var{record}.  Similarly each @var{modifier} is bound to a function to
+be called @code{(@var{modifier} record val)} to set the respective
+field in a @var{record}.
+@end deffn
+
+@noindent
+An example will illustrate typical usage,
+
+@example
+(define-record-type employee-type
+  (make-employee name age salary)
+  employee?
+  (name    get-employee-name)
+  (age     get-employee-age    set-employee-age)
+  (salary  get-employee-salary set-employee-salary))
+@end example
+
+This creates a new employee data type, with name, age and salary
+fields.  Accessor functions are created for each field, but no
+modifier function for the name (the intention in this example being
+that it's established only when an employee object is created).  These
+can all then be used as for example,
+
+@example
+employee-type @result{} #<record-type employee-type>
+
+(define fred (make-employee "Fred" 45 20000.00))
+
+(employee? fred)        @result{} #t
+(get-employee-age fred) @result{} 45
+(set-employee-salary fred 25000.00)  ;; pay rise
+@end example
+
+The functions created by @code{define-record-type} are ordinary
+top-level @code{define}s.  They can be redefined or @code{set!} as
+desired, exported from a module, etc.
+
+@unnumberedsubsubsec Non-toplevel Record Definitions
+
+The SRFI-9 specification explicitly disallows record definitions in a
+non-toplevel context, such as inside @code{lambda} body or inside a
+@var{let} block.  However, Guile's implementation does not enforce that
+restriction.
+
+@unnumberedsubsubsec Custom Printers
+
+You may use @code{set-record-type-printer!} to customize the default printing
+behavior of records.  This is a Guile extension and is not part of SRFI-9.  It
+is located in the @nicode{(srfi srfi-9 gnu)} module.
+
+@deffn {Scheme Syntax} set-record-type-printer! name proc
+Where @var{type} corresponds to the first argument of @code{define-record-type},
+and @var{proc} is a procedure accepting two arguments, the record to print, and
+an output port.
+@end deffn
+
+@noindent
+This example prints the employee's name in brackets, for instance @code{[Fred]}.
+
+@example
+(set-record-type-printer! employee-type
+  (lambda (record port)
+    (write-char #\[ port)
+    (display (get-employee-name record) port)
+    (write-char #\] port)))
+@end example
+
+@unnumberedsubsubsec Functional ``Setters''
+
+@cindex functional setters
+
+When writing code in a functional style, it is desirable to never alter
+the contents of records.  For such code, a simple way to return new
+record instances based on existing ones is highly desirable.
+
+The @code{(srfi srfi-9 gnu)} module extends SRFI-9 with facilities to
+return new record instances based on existing ones, only with one or
+more field values changed---@dfn{functional setters}.  First, the
+@code{define-immutable-record-type} works like
+@code{define-record-type}, except that fields are immutable and setters
+are defined as functional setters.
+
+@deffn {Scheme Syntax} define-immutable-record-type type @* (constructor fieldname @dots{}) @* predicate @* (fieldname accessor [modifier]) @dots{}
+Define @var{type} as a new record type, like @code{define-record-type}.
+However, the record type is made @emph{immutable} (records may not be
+mutated, even with @code{struct-set!}), and any @var{modifier} is
+defined to be a functional setter---a procedure that returns a new
+record instance with the specified field changed, and leaves the
+original unchanged (see example below.)
+@end deffn
+
+@noindent
+In addition, the generic @code{set-field} and @code{set-fields} macros
+may be applied to any SRFI-9 record.
+
+@deffn {Scheme Syntax} set-field record (field sub-fields ...) value
+Return a new record of @var{record}'s type whose fields are equal to
+the corresponding fields of @var{record} except for the one specified by
+@var{field}.
+
+@var{field} must be the name of the getter corresponding to the field of
+@var{record} being ``set''.  Subsequent @var{sub-fields} must be record
+getters designating sub-fields within that field value to be set (see
+example below.)
+@end deffn
+
+@deffn {Scheme Syntax} set-fields record ((field sub-fields ...) value) ...
+Like @code{set-field}, but can be used to set more than one field at a
+time.  This expands to code that is more efficient than a series of
+single @code{set-field} calls.
+@end deffn
+
+To illustrate the use of functional setters, let's assume these two
+record type definitions:
+
+@example
+(define-record-type <address>
+  (address street city country)
+  address?
+  (street  address-street)
+  (city    address-city)
+  (country address-country))
+
+(define-immutable-record-type <person>
+  (person age email address)
+  person?
+  (age     person-age set-person-age)
+  (email   person-email set-person-email)
+  (address person-address set-person-address))
+@end example
+
+@noindent
+First, note that the @code{<person>} record type definition introduces
+named functional setters.  These may be used like this:
+
+@example
+(define fsf-address
+  (address "Franklin Street" "Boston" "USA"))
+
+(define rms
+  (person 30 "rms@@gnu.org" fsf-address))
+
+(and (equal? (set-person-age rms 60)
+             (person 60 "rms@@gnu.org" fsf-address))
+     (= (person-age rms) 30))
+@result{} #t
+@end example
+
+@noindent
+Here, the original @code{<person>} record, to which @var{rms} is bound,
+is left unchanged.
+
+Now, suppose we want to change both the street and age of @var{rms}.
+This can be achieved using @code{set-fields}:
+
+@example
+(set-fields rms
+  ((person-age) 60)
+  ((person-address address-street) "Temple Place"))
+@result{} #<<person> age: 60 email: "rms@@gnu.org"
+  address: #<<address> street: "Temple Place" city: "Boston" country: "USA">>
+@end example
+
+@noindent
+Notice how the above changed two fields of @var{rms}, including the
+@code{street} field of its @code{address} field, in a concise way.  Also
+note that @code{set-fields} works equally well for types defined with
+just @code{define-record-type}.
+
+@node Records
+@subsection Records
+
+A @dfn{record type} is a first class object representing a user-defined
+data type.  A @dfn{record} is an instance of a record type.
+
+Note that in many ways, this interface is too low-level for every-day
+use.  Most uses of records are better served by SRFI-9 records.
+@xref{SRFI-9}.
+
+@deffn {Scheme Procedure} record? obj
+Return @code{#t} if @var{obj} is a record of any type and @code{#f}
+otherwise.
+
+Note that @code{record?} may be true of any Scheme value; there is no
+promise that records are disjoint with other Scheme types.
+@end deffn
+
+@deffn {Scheme Procedure} make-record-type type-name field-names [print]
+Create and return a new @dfn{record-type descriptor}.
+
+@var{type-name} is a string naming the type.  Currently it's only used
+in the printed representation of records, and in diagnostics.
+@var{field-names} is a list of symbols naming the fields of a record
+of the type.  Duplicates are not allowed among these symbols.
+
+@example
+(make-record-type "employee" '(name age salary))
+@end example
+
+The optional @var{print} argument is a function used by
+@code{display}, @code{write}, etc, for printing a record of the new
+type.  It's called as @code{(@var{print} record port)} and should look
+at @var{record} and write to @var{port}.
+@end deffn
+
+@deffn {Scheme Procedure} record-constructor rtd [field-names]
+Return a procedure for constructing new members of the type represented
+by @var{rtd}.  The returned procedure accepts exactly as many arguments
+as there are symbols in the given list, @var{field-names}; these are
+used, in order, as the initial values of those fields in a new record,
+which is returned by the constructor procedure.  The values of any
+fields not named in that list are unspecified.  The @var{field-names}
+argument defaults to the list of field names in the call to
+@code{make-record-type} that created the type represented by @var{rtd};
+if the @var{field-names} argument is provided, it is an error if it
+contains any duplicates or any symbols not in the default list.
+@end deffn
+
+@deffn {Scheme Procedure} record-predicate rtd
+Return a procedure for testing membership in the type represented by
+@var{rtd}.  The returned procedure accepts exactly one argument and
+returns a true value if the argument is a member of the indicated record
+type; it returns a false value otherwise.
+@end deffn
 
 @deffn {Scheme Procedure} record-accessor rtd field-name
 Return a procedure for reading the value of a particular field of a
@@ -2502,331 +2541,509 @@ created the type represented by @var{rtd}.
 @subsection Structures
 @tpindex Structures
 
-[FIXME: this is pasted in from Tom Lord's original guile.texi and should
-be reviewed]
-
-A @dfn{structure type} is a first class user-defined data type.  A
-@dfn{structure} is an instance of a structure type.  A structure type is
-itself a structure.
+A @dfn{structure} is a first class data type which holds Scheme values
+or C words in fields numbered 0 upwards.  A @dfn{vtable} is a structure
+that represents a structure type, giving field types and permissions,
+and an optional print function for @code{write} etc.
 
-Structures are less abstract and more general than traditional records.
-In fact, in Guile Scheme, records are implemented using structures.
+Structures are lower level than records (@pxref{Records}).  Usually,
+when you need to represent structured data, you just want to use
+records.  But sometimes you need to implement new kinds of structured
+data abstractions, and for that purpose structures are useful.  Indeed,
+records in Guile are implemented with structures.
 
 @menu
-* Structure Concepts::          The structure of Structures
-* Structure Layout::            Defining the layout of structure types
-* Structure Basics::            make-, -ref and -set! procedures for structs
-* Vtables::                     Accessing type-specific data
+* Vtables::
+* Structure Basics::
+* Vtable Contents::
+* Meta-Vtables::
+* Vtable Example::
+* Tail Arrays::
 @end menu
 
-@node  Structure Concepts
-@subsubsection Structure Concepts
-
-A structure object consists of a handle, structure data, and a vtable.
-The handle is a Scheme value which points to both the vtable and the
-structure's data.  Structure data is a dynamically allocated region of
-memory, private to the structure, divided up into typed fields.  A
-vtable is another structure used to hold type-specific data.  Multiple
-structures can share a common vtable.
+@node Vtables
+@subsubsection Vtables
 
-Three concepts are key to understanding structures.
+A vtable is a structure type, specifying its layout, and other
+information.  A vtable is actually itself a structure, but there's no
+need to worry about that initially (@pxref{Vtable Contents}.)
 
-@itemize @bullet{}
-@item @dfn{layout specifications}
+@deffn {Scheme Procedure} make-vtable fields [print]
+Create a new vtable.
 
-Layout specifications determine how memory allocated to structures is
-divided up into fields.  Programmers must write a layout specification
-whenever a new type of structure is defined.
+@var{fields} is a string describing the fields in the structures to be
+created.  Each field is represented by two characters, a type letter
+and a permissions letter, for example @code{"pw"}.  The types are as
+follows.
 
-@item @dfn{structural accessors}
-
-Structure access is by field number.   There is only one set of
-accessors common to all structure objects.
+@itemize @bullet{}
+@item
+@code{p} -- a Scheme value.  ``p'' stands for ``protected'' meaning
+it's protected against garbage collection.
 
-@item @dfn{vtables}
+@item
+@code{u} -- an arbitrary word of data (an @code{scm_t_bits}).  At the
+Scheme level it's read and written as an unsigned integer.  ``u''
+stands for ``uninterpreted'' (it's not treated as a Scheme value), or
+``unprotected'' (it's not marked during GC), or ``unsigned long'' (its
+size), or all of these things.
 
-Vtables, themselves structures, are first class representations of
-disjoint sub-types of structures in general.   In most cases, when a
-new structure is created, programmers must specify a vtable for the
-new structure.   Each vtable has a field describing the layout of its
-instances.   Vtables can have additional, user-defined fields as well.
+@item
+@code{s} -- a self-reference.  Such a field holds the @code{SCM} value
+of the structure itself (a circular reference).  This can be useful in
+C code where you might have a pointer to the data array, and want to
+get the Scheme @code{SCM} handle for the structure.  In Scheme code it
+has no use.
 @end itemize
 
+The second letter for each field is a permission code,
 
+@itemize @bullet{}
+@item
+@code{w} -- writable, the field can be read and written.
+@item
+@code{r} -- read-only, the field can be read but not written.
+@item
+@code{o} -- opaque, the field can be neither read nor written at the
+Scheme level.  This can be used for fields which should only be used
+from C code.
+@end itemize
 
-@node  Structure Layout
-@subsubsection Structure Layout
+Here are some examples.  @xref{Tail Arrays}, for information on the
+legacy tail array facility.
 
-When a structure is created, a region of memory is allocated to hold its
-state.  The @dfn{layout} of the structure's type determines how that
-memory is divided into fields.
+@example
+(make-vtable "pw")      ;; one writable field
+(make-vtable "prpw")    ;; one read-only and one writable
+(make-vtable "pwuwuw")  ;; one scheme and two uninterpreted
+@end example
 
-Each field has a specified type.  There are only three types allowed, each
-corresponding to a one letter code.  The allowed types are:
+The optional @var{print} argument is a function called by
+@code{display} and @code{write} (etc) to give a printed representation
+of a structure created from this vtable.  It's called
+@code{(@var{print} struct port)} and should look at @var{struct} and
+write to @var{port}.  The default print merely gives a form like
+@samp{#<struct ADDR:ADDR>} with a pair of machine addresses.
 
-@itemize @bullet{}
-@item 'u' -- unprotected
+The following print function for example shows the two fields of its
+structure.
 
-The field holds binary data that is not GC protected.
+@example
+(make-vtable "prpw"
+             (lambda (struct port)
+               (format port "#<~a and ~a>"
+                       (struct-ref struct 0)
+                       (struct-ref struct 1))))
+@end example
+@end deffn
 
-@item 'p' -- protected
 
-The field holds a Scheme value and is GC protected.
+@node Structure Basics
+@subsubsection Structure Basics
 
-@item 's' -- self
+This section describes the basic procedures for working with
+structures.  @code{make-struct} creates a structure, and
+@code{struct-ref} and @code{struct-set!} access its fields.
+
+@deffn {Scheme Procedure} make-struct vtable tail-size init @dots{}
+@deffnx {Scheme Procedure} make-struct/no-tail vtable init @dots{}
+Create a new structure, with layout per the given @var{vtable}
+(@pxref{Vtables}).
+
+The optional @var{init}@dots{} arguments are initial values for the
+fields of the structure.  This is the only way to
+put values in read-only fields.  If there are fewer @var{init}
+arguments than fields then the defaults are @code{#f} for a Scheme
+field (type @code{p}) or 0 for an uninterpreted field (type @code{u}).
+
+Structures also have the ability to allocate a variable number of
+additional cells at the end, at their tails.  However, this legacy
+@dfn{tail array} facilty is confusing and inefficient, and so we do not
+recommend it.  @xref{Tail Arrays}, for more on the legacy tail array
+interface.
+
+Type @code{s} self-reference fields, permission @code{o} opaque
+fields, and the count field of a tail array are all ignored for the
+@var{init} arguments, ie.@: an argument is not consumed by such a
+field.  An @code{s} is always set to the structure itself, an @code{o}
+is always set to @code{#f} or 0 (with the intention that C code will
+do something to it later), and the tail count is always the given
+@var{tail-size}.
 
-The field holds a Scheme value and is GC protected.  When a structure is
-created with this type of field, the field is initialized to refer to
-the structure's own handle.  This kind of field is mainly useful when
-mixing Scheme and C code in which the C code may need to compute a
-structure's handle given only the address of its malloc'd data.
-@end itemize
+For example,
 
+@example
+(define v (make-vtable "prpwpw"))
+(define s (make-struct v 0 123 "abc" 456))
+(struct-ref s 0) @result{} 123
+(struct-ref s 1) @result{} "abc"
+@end example
+@end deffn
 
-Each field also has an associated access protection.   There are only
-three kinds of protection, each corresponding to a one letter code.
-The allowed protections are:
+@deftypefn {C Function} SCM scm_make_struct (SCM vtable, SCM tail_size, SCM init_list)
+@deftypefnx {C Function} SCM scm_c_make_struct (SCM vtable, SCM tail_size, SCM init, ...)
+@deftypefnx {C Function} SCM scm_c_make_structv (SCM vtable, SCM tail_size, size_t n_inits, scm_t_bits init[])
+There are a few ways to make structures from C.  @code{scm_make_struct}
+takes a list, @code{scm_c_make_struct} takes variable arguments
+terminated with SCM_UNDEFINED, and @code{scm_c_make_structv} takes a
+packed array.
+@end deftypefn
 
-@itemize @bullet{}
-@item 'w' -- writable
+@deffn {Scheme Procedure} struct? obj
+@deffnx {C Function} scm_struct_p (obj)
+Return @code{#t} if @var{obj} is a structure, or @code{#f} if not.
+@end deffn
 
-The field can be read and written.
+@deffn {Scheme Procedure} struct-ref struct n
+@deffnx {C Function} scm_struct_ref (struct, n)
+Return the contents of field number @var{n} in @var{struct}.  The
+first field is number 0.
 
-@item 'r' -- readable
+An error is thrown if @var{n} is out of range, or if the field cannot
+be read because it's @code{o} opaque.
+@end deffn
 
-The field can be read, but not written.
+@deffn {Scheme Procedure} struct-set! struct n value
+@deffnx {C Function} scm_struct_set_x (struct, n, value)
+Set field number @var{n} in @var{struct} to @var{value}.  The first
+field is number 0.
 
-@item 'o' -- opaque
+An error is thrown if @var{n} is out of range, or if the field cannot
+be written because it's @code{r} read-only or @code{o} opaque.  
+@end deffn
 
-The field can be neither read nor written.   This kind
-of protection is for fields useful only to built-in routines.
-@end itemize
+@deffn {Scheme Procedure} struct-vtable struct
+@deffnx {C Function} scm_struct_vtable (struct)
+Return the vtable that describes @var{struct}.
 
-A layout specification is described by stringing together pairs
-of letters: one to specify a field type and one to specify a field
-protection.    For example, a traditional cons pair type object could
-be described as:
+The vtable is effectively the type of the structure.  See @ref{Vtable
+Contents}, for more on vtables.
+@end deffn
 
-@example
-; cons pairs have two writable fields of Scheme data
-"pwpw"
-@end example
 
-A pair object in which the first field is held constant could be:
+@node Vtable Contents
+@subsubsection Vtable Contents
 
-@example
-"prpw"
-@end example
+A vtable is itself a structure.  It has a specific set of fields
+describing various aspects of its @dfn{instances}: the structures
+created from a vtable.  Some of the fields are internal to Guile, some
+of them are part of the public interface, and there may be additional
+fields added on by the user.
 
-Binary fields, (fields of type "u"), hold one @dfn{word} each.  The
-size of a word is a machine dependent value defined to be equal to the
-value of the C expression: @code{sizeof (long)}.
+Every vtable has a field for the layout of their instances, a field for
+the procedure used to print its instances, and a field for the name of
+the vtable itself.  Access to the layout and printer is exposed directly
+via field indexes.  Access to the vtable name is exposed via accessor
+procedures.
 
-The last field of a structure layout may specify a tail array.
-A tail array is indicated by capitalizing the field's protection
-code ('W', 'R' or 'O').   A tail-array field is replaced by
-a read-only binary data field containing an array size.   The array
-size is determined at the time the structure is created.  It is followed
-by a corresponding number of fields of the type specified for the
-tail array.   For example, a conventional Scheme vector can be
-described as:
+@defvr {Scheme Variable} vtable-index-layout
+@defvrx {C Macro} scm_vtable_index_layout
+The field number of the layout specification in a vtable.  The layout
+specification is a symbol like @code{pwpw} formed from the fields
+string passed to @code{make-vtable}, or created by
+@code{make-struct-layout} (@pxref{Meta-Vtables}).
 
 @example
-; A vector is an arbitrary number of writable fields holding Scheme
-; values:
-"pW"
+(define v (make-vtable "pwpw" 0))
+(struct-ref v vtable-index-layout) @result{} pwpw
 @end example
 
-In the above example, field 0 contains the size of the vector and
-fields beginning at 1 contain the vector elements.
+This field is read-only, since the layout of structures using a vtable
+cannot be changed.
+@end defvr
 
-A kind of tagged vector (a constant tag followed by conventional
-vector elements) might be:
+@defvr {Scheme Variable} vtable-index-printer
+@defvrx {C Macro} scm_vtable_index_printer
+The field number of the printer function.  This field contains @code{#f}
+if the default print function should be used.
 
 @example
-"prpW"
+(define (my-print-func struct port)
+  ...)
+(define v (make-vtable "pwpw" my-print-func))
+(struct-ref v vtable-index-printer) @result{} my-print-func
 @end example
 
+This field is writable, allowing the print function to be changed
+dynamically.
+@end defvr
 
-Structure layouts are represented by specially interned symbols whose
-name is a string of type and protection codes.  To create a new
-structure layout, use this procedure:
+@deffn {Scheme Procedure} struct-vtable-name vtable
+@deffnx {Scheme Procedure} set-struct-vtable-name! vtable name
+@deffnx {C Function} scm_struct_vtable_name (vtable)
+@deffnx {C Function} scm_set_struct_vtable_name_x (vtable, name)
+Get or set the name of @var{vtable}.  @var{name} is a symbol and is
+used in the default print function when printing structures created
+from @var{vtable}.
 
-@deffn {Scheme Procedure} make-struct-layout fields
-@deffnx {C Function} scm_make_struct_layout (fields)
-Return a new structure layout object.
+@example
+(define v (make-vtable "pw"))
+(set-struct-vtable-name! v 'my-name)
 
-@var{fields} must be a string made up of pairs of characters
-strung together.  The first character of each pair describes a field
-type, the second a field protection.  Allowed types are 'p' for
-GC-protected Scheme data, 'u' for unprotected binary data, and 's' for
-a field that points to the structure itself.    Allowed protections
-are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque
-fields.  The last field protection specification may be capitalized to
-indicate that the field is a tail-array.
+(define s (make-struct v 0))
+(display s) @print{} #<my-name b7ab3ae0:b7ab3730>
+@end example
 @end deffn
 
 
+@node Meta-Vtables
+@subsubsection Meta-Vtables
 
-@node Structure Basics
-@subsubsection Structure Basics
-
-This section describes the basic procedures for creating and accessing
-structures.
-
-@deffn {Scheme Procedure} make-struct vtable tail_array_size . init
-@deffnx {C Function} scm_make_struct (vtable, tail_array_size, init)
-Create a new structure.
-
-@var{type} must be a vtable structure (@pxref{Vtables}).
-
-@var{tail-elts} must be a non-negative integer.  If the layout
-specification indicated by @var{type} includes a tail-array,
-this is the number of elements allocated to that array.
+As a structure, a vtable also has a vtable, which is also a structure.
+Structures, their vtables, the vtables of the vtables, and so on form a
+tree of structures.  Making a new structure adds a leaf to the tree, and
+if that structure is a vtable, it may be used to create other leaves.
 
-The @var{init1}, @dots{} are optional arguments describing how
-successive fields of the structure should be initialized.  Only fields
-with protection 'r' or 'w' can be initialized, except for fields of
-type 's', which are automatically initialized to point to the new
-structure itself; fields with protection 'o' can not be initialized by
-Scheme programs.
+If you traverse up the tree of vtables, via calling
+@code{struct-vtable}, eventually you reach a root which is the vtable of
+itself:
 
-If fewer optional arguments than initializable fields are supplied,
-fields of type 'p' get default value #f while fields of type 'u' are
-initialized to 0.
+@example
+scheme@@(guile-user)> (current-module)
+$1 = #<directory (guile-user) 221b090>
+scheme@@(guile-user)> (struct-vtable $1)
+$2 = #<record-type module>
+scheme@@(guile-user)> (struct-vtable $2)
+$3 = #<<standard-vtable> 12c30a0>
+scheme@@(guile-user)> (struct-vtable $3)
+$4 = #<<standard-vtable> 12c3fa0>
+scheme@@(guile-user)> (struct-vtable $4)
+$5 = #<<standard-vtable> 12c3fa0>
+scheme@@(guile-user)> <standard-vtable>
+$6 = #<<standard-vtable> 12c3fa0>
+@end example
 
-Structs are currently the basic representation for record-like data
-structures in Guile.  The plan is to eventually replace them with a
-new representation which will at the same time be easier to use and
-more powerful.
+In this example, we can say that @code{$1} is an instance of @code{$2},
+@code{$2} is an instance of @code{$3}, @code{$3} is an instance of
+@code{$4}, and @code{$4}, strangely enough, is an instance of itself.
+The value bound to @code{$4} in this console session also bound to
+@code{<standard-vtable>} in the default environment.
+
+@defvr {Scheme Variable} <standard-vtable>
+A meta-vtable, useful for making new vtables.
+@end defvr
+
+All of these values are structures.  All but @code{$1} are vtables.  As
+@code{$2} is an instance of @code{$3}, and @code{$3} is a vtable, we can
+say that @code{$3} is a @dfn{meta-vtable}: a vtable that can create
+vtables.
+
+With this definition, we can specify more precisely what a vtable is: a
+vtable is a structure made from a meta-vtable.  Making a structure from
+a meta-vtable runs some special checks to ensure that the first field of
+the structure is a valid layout.  Additionally, if these checks see that
+the layout of the child vtable contains all the required fields of a
+vtable, in the correct order, then the child vtable will also be a
+meta-table, inheriting a magical bit from the parent.
+
+@deffn {Scheme Procedure} struct-vtable? obj
+@deffnx {C Function} scm_struct_vtable_p (obj)
+Return @code{#t} if @var{obj} is a vtable structure: an instance of a
+meta-vtable.
+@end deffn
+
+@code{<standard-vtable>} is a root of the vtable tree.  (Normally there
+is only one root in a given Guile process, but due to some legacy
+interfaces there may be more than one.)
+
+The set of required fields of a vtable is the set of fields in the
+@code{<standard-vtable>}, and is bound to @code{standard-vtable-fields}
+in the default environment.  It is possible to create a meta-vtable that
+with additional fields in its layout, which can be used to create
+vtables with additional data:
 
-For more information, see the documentation for @code{make-vtable-vtable}.
-@end deffn
-
-@deffn {Scheme Procedure} struct? x
-@deffnx {C Function} scm_struct_p (x)
-Return @code{#t} iff @var{x} is a structure object, else
-@code{#f}.
-@end deffn
+@example
+scheme@@(guile-user)> (struct-ref $3 vtable-index-layout)
+$6 = pruhsruhpwphuhuhprprpw
+scheme@@(guile-user)> (struct-ref $4 vtable-index-layout)
+$7 = pruhsruhpwphuhuh
+scheme@@(guile-user)> standard-vtable-fields 
+$8 = "pruhsruhpwphuhuh"
+scheme@@(guile-user)> (struct-ref $2 vtable-offset-user)
+$9 = module
+@end example
 
+In this continuation of our earlier example, @code{$2} is a vtable that
+has extra fields, because its vtable, @code{$3}, was made from a
+meta-vtable with an extended layout.  @code{vtable-offset-user} is a
+convenient definition that indicates the number of fields in
+@code{standard-vtable-fields}.
 
-@deffn {Scheme Procedure} struct-ref handle pos
-@deffnx {Scheme Procedure} struct-set! struct n value
-@deffnx {C Function} scm_struct_ref (handle, pos)
-@deffnx {C Function} scm_struct_set_x (struct, n, value)
-Access (or modify) the @var{n}th field of @var{struct}.
+@defvr {Scheme Variable} standard-vtable-fields
+A string containing the orderedq set of fields that a vtable must have.
+@end defvr
 
-If the field is of type 'p', then it can be set to an arbitrary value.
+@defvr {Scheme Variable} vtable-offset-user
+The first index in a vtable that is available for a user.
+@end defvr
 
-If the field is of type 'u', then it can only be set to a non-negative
-integer value small enough to fit in one machine word.
+@deffn {Scheme Procedure} make-struct-layout fields
+@deffnx {C Function} scm_make_struct_layout (fields)
+Return a structure layout symbol, from a @var{fields} string.
+@var{fields} is as described under @code{make-vtable}
+(@pxref{Vtables}).  An invalid @var{fields} string is an error.
 @end deffn
 
+With these definitions, one can define @code{make-vtable} in this way:
 
+@example
+(define* (make-vtable fields #:optional printer)
+  (make-struct/no-tail <standard-vtable>
+    (make-struct-layout fields)
+    printer))
+@end example
 
-@node  Vtables
-@subsubsection Vtables
 
-Vtables are structures that are used to represent structure types.  Each
-vtable contains a layout specification in field
-@code{vtable-index-layout} -- instances of the type are laid out
-according to that specification.  Vtables contain additional fields
-which are used only internally to libguile.  The variable
-@code{vtable-offset-user} is bound to a field number.  Vtable fields
-at that position or greater are user definable.
+@node Vtable Example
+@subsubsection Vtable Example
 
-@deffn {Scheme Procedure} struct-vtable handle
-@deffnx {C Function} scm_struct_vtable (handle)
-Return the vtable structure that describes the type of @var{struct}.
-@end deffn
+Let us bring these points together with an example.  Consider a simple
+object system with single inheritance.  Objects will be normal
+structures, and classes will be vtables with three extra class fields:
+the name of the class, the parent class, and the list of fields.
 
-@deffn {Scheme Procedure} struct-vtable? x
-@deffnx {C Function} scm_struct_vtable_p (x)
-Return @code{#t} iff @var{x} is a vtable structure.
-@end deffn
+So, first we need a meta-vtable that allocates instances with these
+extra class fields.
 
-If you have a vtable structure, @code{V}, you can create an instance of
-the type it describes by using @code{(make-struct V ...)}.  But where
-does @code{V} itself come from?  One possibility is that @code{V} is an
-instance of a user-defined vtable type, @code{V'}, so that @code{V} is
-created by using @code{(make-struct V' ...)}.  Another possibility is
-that @code{V} is an instance of the type it itself describes.  Vtable
-structures of the second sort are created by this procedure:
+@example
+(define <class>
+  (make-vtable
+   (string-append standard-vtable-fields "pwpwpw")
+   (lambda (x port)
+     (format port "<<class> ~a>" (class-name x)))))
+
+(define (class? x)
+  (and (struct? x)
+       (eq? (struct-vtable x) <class>)))
+@end example
 
-@deffn {Scheme Procedure} make-vtable-vtable user_fields tail_array_size . init
-@deffnx {C Function} scm_make_vtable_vtable (user_fields, tail_array_size, init)
-Return a new, self-describing vtable structure.
+To make a structure with a specific meta-vtable, we will use
+@code{make-struct/no-tail}, passing it the computed instance layout and
+printer, as with @code{make-vtable}, and additionally the extra three
+class fields.
 
-@var{user-fields} is a string describing user defined fields of the
-vtable beginning at index @code{vtable-offset-user}
-(see @code{make-struct-layout}).
+@example
+(define (make-class name parent fields)
+  (let* ((fields (compute-fields parent fields))
+         (layout (compute-layout fields)))
+    (make-struct/no-tail <class>
+      layout 
+      (lambda (x port)
+        (print-instance x port))
+      name
+      parent
+      fields)))
+@end example
 
-@var{tail-size} specifies the size of the tail-array (if any) of
-this vtable.
+Instances will store their associated data in slots in the structure: as
+many slots as there are fields.  The @code{compute-layout} procedure
+below can compute a layout, and @code{field-index} returns the slot
+corresponding to a field.
 
-@var{init1}, @dots{} are the optional initializers for the fields of
-the vtable.
+@example
+(define-syntax-rule (define-accessor name n)
+  (define (name obj)
+    (struct-ref obj n)))
+
+;; Accessors for classes
+(define-accessor class-name (+ vtable-offset-user 0))
+(define-accessor class-parent (+ vtable-offset-user 1))
+(define-accessor class-fields (+ vtable-offset-user 2))
+
+(define (compute-fields parent fields)
+  (if parent
+      (append (class-fields parent) fields)
+      fields))
+
+(define (compute-layout fields)
+  (make-struct-layout
+   (string-concatenate (make-list (length fields) "pw"))))
+
+(define (field-index class field)
+  (list-index (class-fields class) field))
+
+(define (print-instance x port)
+  (format port "<~a" (class-name (struct-vtable x)))
+  (for-each (lambda (field idx)
+              (format port " ~a: ~a" field (struct-ref x idx)))
+            (class-fields (struct-vtable x))
+            (iota (length (class-fields (struct-vtable x)))))
+  (format port ">"))
+@end example
 
-Vtables have one initializable system field---the struct printer.
-This field comes before the user fields in the initializers passed
-to @code{make-vtable-vtable} and @code{make-struct}, and thus works as
-a third optional argument to @code{make-vtable-vtable} and a fourth to
-@code{make-struct} when creating vtables:
+So, at this point we can actually make a few classes:
 
-If the value is a procedure, it will be called instead of the standard
-printer whenever a struct described by this vtable is printed.
-The procedure will be called with arguments STRUCT and PORT.
+@example
+(define-syntax-rule (define-class name parent field ...)
+  (define name (make-class 'name parent '(field ...))))
 
-The structure of a struct is described by a vtable, so the vtable is
-in essence the type of the struct.  The vtable is itself a struct with
-a vtable.  This could go on forever if it weren't for the
-vtable-vtables which are self-describing vtables, and thus terminate
-the chain.
+(define-class <surface> #f
+  width height)
 
-There are several potential ways of using structs, but the standard
-one is to use three kinds of structs, together building up a type
-sub-system: one vtable-vtable working as the root and one or several
-"types", each with a set of "instances".  (The vtable-vtable should be
-compared to the class <class> which is the class of itself.)
+(define-class <window> <surface>
+  x y)
+@end example
 
-@lisp
-(define ball-root (make-vtable-vtable "pr" 0))
-
-(define (make-ball-type ball-color)
-  (make-struct ball-root 0
-              (make-struct-layout "pw")
-               (lambda (ball port)
-                 (format port "#<a ~A ball owned by ~A>"
-                         (color ball)
-                         (owner ball)))
-               ball-color))
-(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))
-(define (owner ball) (struct-ref ball 0))
-
-(define red (make-ball-type 'red))
-(define green (make-ball-type 'green))
-
-(define (make-ball type owner) (make-struct type 0 owner))
-
-(define ball (make-ball green 'Nisse))
-ball @result{} #<a green ball owned by Nisse>
-@end lisp
-@end deffn
+And finally, make an instance:
 
-@deffn {Scheme Procedure} struct-vtable-name vtable
-@deffnx {C Function} scm_struct_vtable_name (vtable)
-Return the name of the vtable @var{vtable}.
-@end deffn
+@example
+(make-struct/no-tail <window> 400 300 10 20)
+@result{} <<window> width: 400 height: 300 x: 10 y: 20>
+@end example
 
-@deffn {Scheme Procedure} set-struct-vtable-name! vtable name
-@deffnx {C Function} scm_set_struct_vtable_name_x (vtable, name)
-Set the name of the vtable @var{vtable} to @var{name}.
-@end deffn
+And that's that.  Note that there are many possible optimizations and
+feature enhancements that can be made to this object system, and the
+included GOOPS system does make most of them.  For more simple use
+cases, the records facility is usually sufficient.  But sometimes you
+need to make new kinds of data abstractions, and for that purpose,
+structs are here.
+
+@node Tail Arrays
+@subsubsection Tail Arrays
+
+Guile's structures have a facility whereby each instance of a vtable can
+contain a variable-length tail array of values.  The length of the tail
+array is stored in the structure.  This facility was originally intended
+to allow C code to expose raw C structures with word-sized tail arrays
+to Scheme.
+
+However, the tail array facility is confusing and doesn't work very
+well.  It is very rarely used, but it insinuates itself into all
+invocations of @code{make-struct}.  For this reason the clumsily-named
+@code{make-struct/no-tail} procedure can actually be more elegant in
+actual use, because it doesn't have a random @code{0} argument stuck in
+the middle.
+
+Tail arrays also inhibit optimization by allowing instances to affect
+their shapes.  In the absence of tail arrays, all instances of a given
+vtable have the same number and kinds of fields.  This uniformity can be
+exploited by the runtime and the optimizer.  The presence of tail arrays
+make some of these optimizations more difficult.
+
+Finally, the tail array facility is ad-hoc and does not compose with the
+rest of Guile.  If a Guile user wants an array with user-specified
+length, it's best to use a vector.  It is more clear in the code, and
+the standard optimization techniques will do a good job with it.
+
+That said, we should mention some details about the interface.  A vtable
+that has tail array has upper-case permission descriptors: @code{W},
+@code{R} or @code{O}, correspoding to tail arrays of writable,
+read-only, or opaque elements.  A tail array permission descriptor may
+only appear in the last element of a vtable layout.
+
+For exampple, @samp{pW} indicates a tail of writable Scheme-valued
+fields.  The @samp{pW} field itself holds the tail size, and the tail
+fields come after it.
 
-@deffn {Scheme Procedure} struct-vtable-tag handle
-@deffnx {C Function} scm_struct_vtable_tag (handle)
-Return the vtable tag of the structure @var{handle}.
-@end deffn
+@example
+(define v (make-vtable "prpW")) ;; one fixed then a tail array
+(define s (make-struct v 6 "fixed field" 'x 'y))
+(struct-ref s 0) @result{} "fixed field"
+(struct-ref s 1) @result{} 2    ;; tail size
+(struct-ref s 2) @result{} x    ;; tail array ...
+(struct-ref s 3) @result{} y
+(struct-ref s 4) @result{} #f
+@end example
 
 
 @node Dictionary Types
@@ -2836,7 +3053,7 @@ A @dfn{dictionary} object is a data structure used to index
 information in a user-defined way.  In standard Scheme, the main
 aggregate data types are lists and vectors.  Lists are not really
 indexed at all, and vectors are indexed only by number
-(e.g. @code{(vector-ref foo 5)}).  Often you will find it useful
+(e.g.@: @code{(vector-ref foo 5)}).  Often you will find it useful
 to index your data on some other type; for example, in a library
 catalog you might want to look up a book by the name of its
 author.  Dictionaries are used to help you organize information in
@@ -2869,10 +3086,9 @@ of tools for using either association lists or hash tables.
 @subsection Association Lists
 @tpindex Association Lists
 @tpindex Alist
-
-@cindex Association List
-@cindex Alist
-@cindex Database
+@cindex association List
+@cindex alist
+@cindex database
 
 An association list is a conventional data structure that is often used
 to implement simple key-value databases.  It consists of a list of
@@ -3067,11 +3283,10 @@ association list.
 @rnindex assv
 @rnindex assoc
 
-@code{assq}, @code{assv} and @code{assoc} take an alist and a key as
-arguments and return the entry for that key if an entry exists, or
-@code{#f} if there is no entry for that key.  Note that, in the cases
-where an entry exists, these procedures return the complete entry, that
-is @code{(KEY . VALUE)}, not just the value.
+@code{assq}, @code{assv} and @code{assoc} find the entry in an alist
+for a given key, and return the @code{(@var{key} . @var{value})} pair.
+@code{assq-ref}, @code{assv-ref} and @code{assoc-ref} do a similar
+lookup, but return just the @var{value}.
 
 @deffn {Scheme Procedure} assq key alist
 @deffnx {Scheme Procedure} assv key alist
@@ -3079,26 +3294,14 @@ is @code{(KEY . VALUE)}, not just the value.
 @deffnx {C Function} scm_assq (key, alist)
 @deffnx {C Function} scm_assv (key, alist)
 @deffnx {C Function} scm_assoc (key, alist)
-Fetch the entry in @var{alist} that is associated with @var{key}.  To
-decide whether the argument @var{key} matches a particular entry in
-@var{alist}, @code{assq} compares keys with @code{eq?}, @code{assv}
-uses @code{eqv?} and @code{assoc} uses @code{equal?}.  If @var{key}
-cannot be found in @var{alist} (according to whichever equality
-predicate is in use), then return @code{#f}.  These functions
-return the entire alist entry found (i.e. both the key and the value).
-@end deffn
-
-@code{assq-ref}, @code{assv-ref} and @code{assoc-ref}, on the other
-hand, take an alist and a key and return @emph{just the value} for that
-key, if an entry exists.  If there is no entry for the specified key,
-these procedures return @code{#f}.
-
-This creates an ambiguity: if the return value is @code{#f}, it means
-either that there is no entry with the specified key, or that there
-@emph{is} an entry for the specified key, with value @code{#f}.
-Consequently, @code{assq-ref} and friends should only be used where it
-is known that an entry exists, or where the ambiguity doesn't matter
-for some other reason.
+Return the first entry in @var{alist} with the given @var{key}.  The
+return is the pair @code{(KEY . VALUE)} from @var{alist}.  If there's
+no matching entry the return is @code{#f}.
+
+@code{assq} compares keys with @code{eq?}, @code{assv} uses
+@code{eqv?} and @code{assoc} uses @code{equal?}.  See also SRFI-1
+which has an extended @code{assoc} (@ref{SRFI-1 Association Lists}).
+@end deffn
 
 @deffn {Scheme Procedure} assq-ref alist key
 @deffnx {Scheme Procedure} assv-ref alist key
@@ -3106,18 +3309,22 @@ for some other reason.
 @deffnx {C Function} scm_assq_ref (alist, key)
 @deffnx {C Function} scm_assv_ref (alist, key)
 @deffnx {C Function} scm_assoc_ref (alist, key)
-Like @code{assq}, @code{assv} and @code{assoc}, except that only the
-value associated with @var{key} in @var{alist} is returned.  These
-functions are equivalent to
+Return the value from the first entry in @var{alist} with the given
+@var{key}, or @code{#f} if there's no such entry.
 
-@lisp
-(let ((ent (@var{associator} @var{key} @var{alist})))
-  (and ent (cdr ent)))
-@end lisp
+@code{assq-ref} compares keys with @code{eq?}, @code{assv-ref} uses
+@code{eqv?} and @code{assoc-ref} uses @code{equal?}.
+
+Notice these functions have the @var{key} argument last, like other
+@code{-ref} functions, but this is opposite to what @code{assq}
+etc above use.
 
-where @var{associator} is one of @code{assq}, @code{assv} or @code{assoc}.
+When the return is @code{#f} it can be either @var{key} not found, or
+an entry which happens to have value @code{#f} in the @code{cdr}.  Use
+@code{assq} etc above if you need to differentiate these cases.
 @end deffn
 
+
 @node Removing Alist Entries
 @subsubsection Removing Alist Entries
 
@@ -3203,7 +3410,8 @@ whole is not a proper list:
 (assoc "mary" '((1 . 2) ("key" . "door") . "open sesame"))
 @result{}
 ERROR: In procedure assoc in expression (assoc "mary" (quote #)):
-ERROR: Wrong type argument in position 2 (expecting association list): ((1 . 2) ("key" . "door") . "open sesame")
+ERROR: Wrong type argument in position 2 (expecting
+   association list): ((1 . 2) ("key" . "door") . "open sesame")
 
 (sloppy-assoc "mary" '((1 . 2) ("key" . "door") . "open sesame"))
 @result{}
@@ -3217,7 +3425,8 @@ Secondly, if one of the entries in the specified alist is not a pair:
 (assoc 2 '((1 . 1) 2 (3 . 9)))
 @result{}
 ERROR: In procedure assoc in expression (assoc 2 (quote #)):
-ERROR: Wrong type argument in position 2 (expecting association list): ((1 . 1) 2 (3 . 9))
+ERROR: Wrong type argument in position 2 (expecting
+   association list): ((1 . 1) 2 (3 . 9))
 
 (sloppy-assoc 2 '((1 . 1) 2 (3 . 9)))
 @result{}
@@ -3288,12 +3497,152 @@ capitals
     ("Florida" . "Tallahassee"))
 @end lisp
 
+@node VHashes
+@subsection VList-Based Hash Lists or ``VHashes''
+
+@cindex VList-based hash lists
+@cindex VHash
+
+The @code{(ice-9 vlist)} module provides an implementation of @dfn{VList-based
+hash lists} (@pxref{VLists}).  VList-based hash lists, or @dfn{vhashes}, are an
+immutable dictionary type similar to association lists that maps @dfn{keys} to
+@dfn{values}.  However, unlike association lists, accessing a value given its
+key is typically a constant-time operation.
+
+The VHash programming interface of @code{(ice-9 vlist)} is mostly the same as
+that of association lists found in SRFI-1, with procedure names prefixed by
+@code{vhash-} instead of @code{alist-} (@pxref{SRFI-1 Association Lists}).
+
+In addition, vhashes can be manipulated using VList operations:
+
+@example
+(vlist-head (vhash-consq 'a 1 vlist-null))
+@result{} (a . 1)
+
+(define vh1 (vhash-consq 'b 2 (vhash-consq 'a 1 vlist-null)))
+(define vh2 (vhash-consq 'c 3 (vlist-tail vh1)))
+
+(vhash-assq 'a vh2)
+@result{} (a . 1)
+(vhash-assq 'b vh2)
+@result{} #f
+(vhash-assq 'c vh2)
+@result{} (c . 3)
+(vlist->list vh2)
+@result{} ((c . 3) (a . 1))
+@end example
+
+However, keep in mind that procedures that construct new VLists
+(@code{vlist-map}, @code{vlist-filter}, etc.) return raw VLists, not vhashes:
+
+@example
+(define vh (alist->vhash '((a . 1) (b . 2) (c . 3)) hashq))
+(vhash-assq 'a vh)
+@result{} (a . 1)
+
+(define vl
+  ;; This will create a raw vlist.
+  (vlist-filter (lambda (key+value) (odd? (cdr key+value))) vh))
+(vhash-assq 'a vl)
+@result{} ERROR: Wrong type argument in position 2
+
+(vlist->list vl)
+@result{} ((a . 1) (c . 3))
+@end example
+
+@deffn {Scheme Procedure} vhash? obj
+Return true if @var{obj} is a vhash.
+@end deffn
+
+@deffn {Scheme Procedure} vhash-cons key value vhash [hash-proc]
+@deffnx {Scheme Procedure} vhash-consq key value vhash
+@deffnx {Scheme Procedure} vhash-consv key value vhash
+Return a new hash list based on @var{vhash} where @var{key} is associated with
+@var{value}, using @var{hash-proc} to compute the hash of @var{key}.
+@var{vhash} must be either @code{vlist-null} or a vhash returned by a previous
+call to @code{vhash-cons}.  @var{hash-proc} defaults to @code{hash} (@pxref{Hash
+Table Reference, @code{hash} procedure}).  With @code{vhash-consq}, the
+@code{hashq} hash function is used; with @code{vhash-consv} the @code{hashv}
+hash function is used.
+
+All @code{vhash-cons} calls made to construct a vhash should use the same
+@var{hash-proc}.  Failing to do that, the result is undefined.
+@end deffn
+
+@deffn {Scheme Procedure} vhash-assoc key vhash [equal? [hash-proc]]
+@deffnx {Scheme Procedure} vhash-assq key vhash
+@deffnx {Scheme Procedure} vhash-assv key vhash
+Return the first key/value pair from @var{vhash} whose key is equal to @var{key}
+according to the @var{equal?} equality predicate (which defaults to
+@code{equal?}), and using @var{hash-proc} (which defaults to @code{hash}) to
+compute the hash of @var{key}.  The second form uses @code{eq?} as the equality
+predicate and @code{hashq} as the hash function; the last form uses @code{eqv?}
+and @code{hashv}.
+
+Note that it is important to consistently use the same hash function for
+@var{hash-proc} as was passed to @code{vhash-cons}.  Failing to do that, the
+result is unpredictable.
+@end deffn
+
+@deffn {Scheme Procedure} vhash-delete key vhash [equal? [hash-proc]]
+@deffnx {Scheme Procedure} vhash-delq key vhash
+@deffnx {Scheme Procedure} vhash-delv key vhash
+Remove all associations from @var{vhash} with @var{key}, comparing keys with
+@var{equal?} (which defaults to @code{equal?}), and computing the hash of
+@var{key} using @var{hash-proc} (which defaults to @code{hash}).  The second
+form uses @code{eq?} as the equality predicate and @code{hashq} as the hash
+function; the last one uses @code{eqv?} and @code{hashv}.
+
+Again the choice of @var{hash-proc} must be consistent with previous calls to
+@code{vhash-cons}.
+@end deffn
+
+@deffn {Scheme Procedure} vhash-fold proc init vhash
+@deffnx {Scheme Procedure} vhash-fold-right proc init vhash
+Fold over the key/value elements of @var{vhash} in the given direction,
+with each call to @var{proc} having the form @code{(@var{proc} key value
+result)}, where @var{result} is the result of the previous call to
+@var{proc} and @var{init} the value of @var{result} for the first call
+to @var{proc}.
+@end deffn
+
+@deffn {Scheme Procedure} vhash-fold* proc init key vhash [equal? [hash]]
+@deffnx {Scheme Procedure} vhash-foldq* proc init key vhash
+@deffnx {Scheme Procedure} vhash-foldv* proc init key vhash
+Fold over all the values associated with @var{key} in @var{vhash}, with each
+call to @var{proc} having the form @code{(proc value result)}, where
+@var{result} is the result of the previous call to @var{proc} and @var{init} the
+value of @var{result} for the first call to @var{proc}.
+
+Keys in @var{vhash} are hashed using @var{hash} are compared using @var{equal?}.
+The second form uses @code{eq?} as the equality predicate and @code{hashq} as
+the hash function; the third one uses @code{eqv?} and @code{hashv}.
+
+Example:
+
+@example
+(define vh
+  (alist->vhash '((a . 1) (a . 2) (z . 0) (a . 3))))
+
+(vhash-fold* cons '() 'a vh)
+@result{} (3 2 1)
+
+(vhash-fold* cons '() 'z vh)
+@result{} (0)
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} alist->vhash alist [hash-proc]
+Return the vhash corresponding to @var{alist}, an association list, using
+@var{hash-proc} to compute key hashes.  When omitted, @var{hash-proc} defaults
+to @code{hash}.
+@end deffn
+
+
 @node Hash Tables
 @subsection Hash Tables
 @tpindex Hash Tables
 
-@c FIXME::martin: Review me!
-
 Hash tables are dictionaries which offer similar functionality as
 association lists: They provide a mapping from keys to values.  The
 difference is that association lists need time linear in the size of
@@ -3311,8 +3660,6 @@ procedures (@pxref{Lists}) for working with them.
 @node Hash Table Examples
 @subsubsection Hash Table Examples
 
-@c FIXME::martin: Review me!
-
 For demonstration purposes, this section gives a few usage examples of
 some hash table procedures, together with some explanation what they do.
 
@@ -3322,14 +3669,21 @@ populate it with two key/value pairs.
 @lisp
 (define h (make-hash-table 31))
 
-(hashq-create-handle! h 'foo "bar")
+;; This is an opaque object
+h
 @result{}
-(foo . "bar")
+#<hash-table 0/31>
+
+;; Inserting into a hash table can be done with hashq-set!
+(hashq-set! h 'foo "bar")
+@result{}
+"bar"
 
-(hashq-create-handle! h 'braz "zonk")
+(hashq-set! h 'braz "zonk")
 @result{}
-(braz . "zonk")
+"zonk"
 
+;; Or with hash-create-handle!
 (hashq-create-handle! h 'frob #f)
 @result{}
 (frob . #f)
@@ -3372,8 +3726,9 @@ key is not found.
 #f
 @end lisp
 
-There is no procedure for calculating the number of key/value-pairs in
-a hash table, but @code{hash-fold} can be used for doing exactly that.
+Interesting results can be computed by using @code{hash-fold} to work
+through each element.  This example will count the total number of
+elements:
 
 @lisp
 (hash-fold (lambda (key value seed) (+ 1 seed)) 0 h)
@@ -3381,6 +3736,24 @@ a hash table, but @code{hash-fold} can be used for doing exactly that.
 3
 @end lisp
 
+The same thing can be done with the procedure @code{hash-count}, which
+can also count the number of elements matching a particular predicate.
+For example, count the number of elements with string values:
+
+@lisp
+(hash-count (lambda (key value) (string? value)) h)
+@result{}
+2
+@end lisp
+
+Counting all the elements is a simple task using @code{const}:
+
+@lisp
+(hash-count (const #t) h)
+@result{}
+3
+@end lisp
+
 @node Hash Table Reference
 @subsubsection Hash Table Reference
 
@@ -3397,18 +3770,17 @@ A single @code{make-hash-table} creates a hash table suitable for use
 with any set of functions, but it's imperative that just one set is
 then used consistently, or results will be unpredictable.
 
-@sp 1
 Hash tables are implemented as a vector indexed by a hash value formed
 from the key, with an association list of key/value pairs for each
 bucket in case distinct keys hash together.  Direct access to the
 pairs in those lists is provided by the @code{-handle-} functions.
 
-When the number of table entries goes above a threshold the vector is
-increased and the entries rehashed, to prevent the bucket lists
-becoming too long and slowing down accesses.  When the number of
-entries goes below a threshold the vector is decreased to save space.
+When the number of entries in a hash table goes above a threshold, the
+vector is made larger and the entries are rehashed, to prevent the
+bucket lists from becoming too long and slowing down accesses.  When the
+number of entries goes below a threshold, the vector is shrunk to save
+space.
 
-@sp 1
 For the @code{hashx-} ``extended'' routines, an application supplies a
 @var{hash} function producing an integer index like @code{hashq} etc
 below, and an @var{assoc} alist search function like @code{assq} etc
@@ -3440,13 +3812,10 @@ addition to @code{hashq} etc below, include @code{symbol-hash}
 (@pxref{String Comparison}), and @code{char-set-hash}
 (@pxref{Character Set Predicates/Comparison}).
 
-Note that currently, unfortunately, there's no @code{hashx-remove!}
-function, which rather limits the usefulness of the @code{hashx-}
-routines.
-
 @sp 1
 @deffn {Scheme Procedure} make-hash-table [size]
-Create a new hash table, with an optional minimum vector @var{size}.
+Create a new hash table object, with an optional minimum
+vector @var{size}.
 
 When @var{size} is given, the table vector will still grow and shrink
 automatically, as described above, but with @var{size} as a minimum.
@@ -3457,12 +3826,12 @@ added.
 
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
-Return @code{#t} if @var{obj} is a hash table.
+Return @code{#t} if @var{obj} is a abstract hash table object.
 @end deffn
 
 @deffn {Scheme Procedure} hash-clear! table
 @deffnx {C Function} scm_hash_clear_x (table)
-Remove all items from TABLE (without triggering a resize).
+Remove all items from @var{table} (without triggering a resize).
 @end deffn
 
 @deffn {Scheme Procedure} hash-ref table key [dflt]
@@ -3494,9 +3863,11 @@ If it's not present then a new entry is created.
 @deffn {Scheme Procedure} hash-remove! table key
 @deffnx {Scheme Procedure} hashq-remove! table key
 @deffnx {Scheme Procedure} hashv-remove! table key
+@deffnx {Scheme Procedure} hashx-remove! hash assoc table key
 @deffnx {C Function} scm_hash_remove_x (table, key)
 @deffnx {C Function} scm_hashq_remove_x (table, key)
 @deffnx {C Function} scm_hashv_remove_x (table, key)
+@deffnx {C Function} scm_hashx_remove_x (hash, assoc, table, key)
 Remove any association for @var{key} in the given hash @var{table}.
 If @var{key} is not in @var{table} then nothing is done.
 @end deffn
@@ -3610,6 +3981,13 @@ For example, the following returns a count of how many keys in
 @end example
 @end deffn
 
+@deffn {Scheme Procedure} hash-count pred table
+@deffnx {C Function} scm_hash_count (pred, table)
+Return the number of elements in the given hash @var{table} that cause
+@code{(@var{pred} @var{key} @var{value})} to return true.  To quickly
+determine the total number of elements, use @code{(const #t)} for
+@var{pred}.
+@end deffn
 
 @c Local Variables:
 @c TeX-master: "guile.texi"