[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

preliminary report of workshop



Greater standardization of the Scheme programming language was
the object of a workshop held at Brandeis University on 22-23
October 1984.  The participants were Hal Abelson (MIT), Norman
Adams (Yale), David Bartley (TI), Gary Brooks (TI, IU), William
Clinger (IU), Dan Friedman (IU), Robert Halstead (MIT), Chris
Hanson (MIT), Chris Haynes (IU), Eugene Kohlbecker (IU), Don
Oxley (TI), Jonathan Rees (MIT), Bill Rozas (MIT), Gerald Sussman
(MIT), and Mitchell Wand (IU, Brandeis).  Kent Pitman (MIT)
contributed to the agenda but was unable to attend the sessions.

The participants, through some compromises, were able to reach
unanimous agreement on an essential core language and on the
syntax and semantics of a number of optional features that most
implementations will want to support.  A few issues were deferred
to committees:  input/output, additional operations on strings,
and the gruesome details of numbers and arithmetic.

This preliminary report is intended for implementors that need to
know the results of the workshop now in order to conform to the
standards that were agreed upon.  Comments are solicited as well.
The final report is being written by William Clinger and is
expected by 1 March 1985.

----------------------------------------------------------------

    Preliminary Report of the October 1984 Workshop on Scheme


Essential features must be supported by every implementation of
Scheme.  Programs written in Essential Scheme will run on any
implementation of Scheme worthy of the name.

Optional features may not be supported by every implementation,
but those that do support a feature will use the same syntax and
semantics for the feature.  Hence code that makes use of optional
features will run on any implementation of Scheme that supplies
the optional features.

Optional features are indicated in this preliminary report by
prefixing them with "Optionally, ".

An implementation may extend the language in any way whatsoever,
but code that makes use of extended features is not portable.

This preliminary report is divided into the following sections:

	lexical features
	special constants and variables
	special forms
	data types
	procedures

----------------------------------------------------------------

			Lexical features


The following characters are whitespace characters:

    The space character.
    The tab character.
    The newline character.
    The carriage return character.
    The line feed character.
    The form feed character.

The following characters are delimiters that terminate symbols:

    Any whitespace character is a delimiter.
    Left parenthesis is a delimiter.
    Right parenthesis is a delimiter.
    Left square bracket is a delimiter.
    Right square bracket is a delimiter.
    Left curly brace is a delimiter.
    Right curly brace is a delimiter.
    Semicolon is a delimiter.
    Double quote is a delimiter.
    End of file is a delimiter.

Left and right square brackets and left and right curly braces
have not yet been assigned any meaning but they are reserved for
future use.

The period is not a delimiter that terminates symbols.

Optionally, the following characters may be delimiters that
terminate symbols:

    Single quote.
    Backquote.
    Sharp sign.

It is not specified whether or not the vertical bar is a
delimiter that terminates symbols.

No escape character is specified for use in symbols.  (There is
widespread agreement that "slashification" of characters within
symbols is a relic that ought to be abandoned.)

Lists may be notated in the traditional way using an opening left
parentheses and a closing right parentheses.  Whitespace may
follow the opening parenthesis and precede the closing
parenthesis.  The empty list may be notated as ().  Conses may be
notated as (x . y), where x and y are any notations for an
object.  Whitespace is required on each side of the period.
Possibly improper lists may be notated in the traditional way as
(... x . y).  (foo . ()) reads the same as (foo), but (foo . nil)
does not.

Strings are delimited by double quotes.  Double quotes may be
included inside strings by escaping them with backslash
characters.  Backslashes may be included inside strings by
escaping them with backslashes.

'x reads as (quote x) .

Optionally, backquote, comma, and comma at-sign (",@") work in
the traditional way to one level of nesting.  (Implementations
that support this feature may in fact allow arbitrary levels of
nesting, but the workshop chose not to take the time to determine
the right semantics for deeper levels of nesting.  It appears
that at least one major implementation of Lisp has gotten it
wrong in the past.)

Comments are opened by semicolons and closed by end of line or
end of file characters.

Optionally, sharp sign macros are introduced by a sharp sign.
Implementations that don't have sharp sign macros must still
support #!true, #!false, and the #(...) notation for vectors.

The workshop chose not to specify a notation for unreadable
objects.  (Hal Abelson suggested that the machine should
pronounce them rather than print them.)

Vectors may be written using #(...) notation.

The default input radix is decimal.

Optionally, binary numbers may be written using the #b notation.
Optionally, octal numbers may be written using the #o notation.
Optionally, decimal numbers may be written using the #d notation.
Optionally, hexadecimal numbers may be written using the #x
notation.

Optionally, special characters may be written using the #\
notation.  If this feature is supported, then the Common Lisp
names for special characters must be supported.

#!true reads as a true object, and #!false reads as a false object.

Integers may be written in the usual way, with or without signs.

Optionally, numbers may be written using decimal points and/or
exponents.  The precise notations and semantics were deferred to
the numbers committee.

Symbols may be written as sequences of characters that contain no
special characters and begin with a character that cannot begin a
number.  (This is not to imply that there are no other symbols;
in particular +, -, *, /, 1+, and -1+ should be symbols.)  The
precise language for symbols is not otherwise specified.

When the 26 letters of the alphabet are used to write a symbol,
case is immaterial unless overridden by slashification.  (This is
not to say that slashification is an essential or optional
feature, but rather to allow for implementations that have
slashification as an extended feature.)

----------------------------------------------------------------

		 Special variables and constants


The empty list counts as false in conditional expressions. (There
may be other false values as well.)  The empty list is not the
same as the symbol NIL.  (This is incompatible with most other
Lisps.)

#!false reads as a false value that evaluates to itself.  #!true
reads as a true value that evaluates to itself.  Case is
immaterial.

Optionally, #!null reads as the empty list.  Case is immaterial.

Optionally, the symbol NIL evaluates to the empty list.
Optionally, NIL evaluates to some false value.
Optionally, T evaluates to some true value.

----------------------------------------------------------------

			  Special forms


The order of evaluation within an application is not specified.


(QUOTE object) evaluates to object.


(LAMBDA varspec expr ...) evaluates to a procedure.  varspec may
be a proper list of symbols, a symbol, or an improper list of
symbols.  The body of the LAMBDA is an implicit BEGIN.  The
semantics associated with the various possibilities for varspec
are as described in the MIT Scheme manual and the T manual.


(LET ((id1 expr1) ...) expr ...) is equivalent to

    ((LAMBDA (id1 ...) expr ...) expr1 ...)


(LETREC ((i1 expr1) ...) expr ...) binds i1... to fresh
locations holding unspecified values, evaluates expr1... in some
unspecified order in the resulting environment, and then
evaluates expr... .  The expr1... expressions do not have to be
lambda expressions, but they must be evaluable without referring
to any of i1... .  If this restriction is violated, the effect of
the LETREC is unspecified, and some implementations may signal an
error.  The body of the LETREC is an implicit BEGIN.


(IF test consequent alternative) is an if-then-else expression as
described in the Revised Report on Scheme.  The alternative may
be omitted when evaluation is for effect rather than for value.
It is a mistake for a program to make use of the value returned
by an (IF test consequent) expression, and some implementations
may signal an error if the value is used when test evaluates
false.  [Should implementations be allowed to signal an error
when the value of (IF test consequent) is used and test evaluates
true?]


(COND clause1 ...) is similar to the COND expressions of Common
Lisp.  Each clause is a list of one or more forms, and the
semantics is as described by cases below:

    (COND (form) ...) is equivalent to

        (OR form (COND ...)) where OR is the optional special
            form described below.

    (COND (form1 form2 ...) ...) is equivalent to

        (IF form1
            (BEGIN form2 ...)
            (COND ...))

    (COND) returns an unspecified value; it is a mistake to use
    that value, and some implementations may signal an error if
    it is used.

Also, in each implementation either ELSE must be a standard
variable whose value is initially true or else

    (COND (ELSE form2 ...)) must be equivalent to

        (BEGIN form2 ...) .


(SET! id expr) evaluates expr and stores the result in the
location denoted by the identifier id.  If id is does not denote
a location, as would happen for example if id were unbound, then
the effect of the SET! is not specified, and some implementations
may signal an error.  SET! forms should be evaluated for effect,
for they return an unspecified value; it is a mistake for a
program to use the value returned by a SET! expression, and some
implementations may signal an error if it is used.


(DEFINE id expr) allows top-level definitions of variables.  Its
semantics at top level are similar to the semantics of
(SET! id expr).  The difference is that if id is not already
bound to a location, then the DEFINE form binds id before
performing the assignment, whereas it would be a mistake to
perform a SET! on an unbound identifier.  The value returned by a
DEFINE form is not specified.


(BEGIN form1 ...) evaluates form1... sequentially, returning the
value of the last form.  There should be at least one form in the
body of the BEGIN.


Optionally, (LET name ((id1 expr1) ...) expr ...) is like the LET
described earlier except that it also binds name to the procedure
resulting from (LAMBDA (id1 ...) expr ...) .  This optional
feature supersedes the ITERATE special form described in the
Revised Report on Scheme.


Optionally, (LET* ((id1 expr1) ...) expr ...) is as described in
the T manual.


Optionally, (REC id expr) is equivalent to

    (LETREC ((id expr)) id).


Optionally, (NAMED-LAMBDA (name var1 ...) expr ...) is equivalent
to
    (REC name (LAMBDA (var1 ...) expr ...))

where REC is as above.  (Some implementations may provide better
debugging information when the NAMED-LAMBDA form is used,
however.)


Optionally, the DO special form is as in Common Lisp, except that
it does not bind the identifier RETURN.  [The final report will
give a more careful account of the syntax and semantics of DO.]


Optionally,

    (COND (form1 => form2) ...) is equivalent to

        (LET ((form1_result form1)
              (thunk2 (lambda () form2))
              (thunk3 (lambda () (COND ...))))
          (IF form1_result
              ((thunk2) form1_result)
              (thunk3)))


Optionally, the CASE special form performs a dispatch.  In

    (CASE expr0
          (selector1 form1 ...)
          (selector2 form2 ...)
          ...
          (ELSE else_form1 ...))

each selector should be a list of values.  The selectors are not
evaluated.  When the CASE expression is evaluated, expr0 is
evaluated and its result is compared against successive selectors
using the MEMV procedure until a match is found.  When a match is
found the forms associated with the matching selector are
evaluated in an implicit BEGIN and the result of that BEGIN is
returned as the value of the entire CASE expression.  If none of
the selectors yield a match, then the else_forms are evaluated in
an implicit BEGIN and the result returned as the value of the
CASE expression.  The ELSE clause may also be omitted, in which
case the value of the CASE expression is unspecified when none of
the selectors match; it is a mistake to use the result of the CASE
expression when that happens, and some implementations may signal
an error if the result is used.


Optionally, the special form (AND form1 ...) is as described in
the Revised Report on Scheme.  (This special form goes by the
name of CONJUNCTION in the Abelson & Sussman book.)


Optionally, the special form (OR form1 ...) is as described in
the Revised Report on Scheme.  (This special form goes by the
name of DISJUNCTION in the Abelson & Sussman book.)


Optionally, DEFINE may be used for internal definitions as in MIT
Scheme and in the book by Abelson and Sussman.  If allowed at
all, internal definitions are permitted only in the bodies of
LAMBDA, LET, LETREC, and similar binding constructs.  Furthermore
they must precede the rest of the body.  With these restrictions,
the semantics of internal definitions can be explained in terms
of LETREC.  For example,

    (LAMBDA (x)
      (DEFINE foo ...)
      (DEFINE bar ...)
      ...)

is equivalent to

    (LAMBDA (x)
      (LETREC ((foo ...)
               (bar ...))
        ...))

Also

    (LAMBDA (...)
      (BEGIN (DEFINE ...)
             (DEFINE ...))
      ...)

must be treated the same as

    (LAMBDA (...)
      (DEFINE ...)
      (DEFINE ...)
      ...)

and so on.


Optionally, DEFINE forms may permit MIT's extended syntax in
which

    (DEFINE (foo ...) ...) is equivalent to

    (DEFINE foo (REC foo (LAMBDA (...) ...)))

where REC is the optional special form described above, and

    (DEFINE ((foo ...) ...) ...) is equivalent to

    (DEFINE (foo ...) (LAMBDA (...) ...)),

and so on.


Optionally, (DEFINE! id expr) is equivalent to (DEFINE id expr)
when typed at the top level.  Within code, (DEFINE! id expr) is
equivalent to (SET! id expr) unless id is unbound, in which case
the DEFINE! form creates a new top level binding for id before
performing the assignment.  The value returned by a DEFINE! form
is not specified, and it is a mistake to use it.


Optionally, (DEFREC! id expr) is equivalent to
(DEFINE! id (REC id expr)).


Optionally, SEQUENCE is synonymous with BEGIN.  (SEQUENCE is for
compatibility with the Abelson and Sussman text, and should not
be used in new code.)

----------------------------------------------------------------

			   Data types


All Scheme objects have unlimited extent.

(The workshop did not require that any data types be disjoint.
In theory, therefore, strings could be indistinguishable from
lists of numbers, and would therefore be printed as lists of
numbers by the standard printer.  Until we can agree on a better
standard, we have to rely on the good judgement of implementors
to avoid such problems.)

There is an object that represents both false and the empty list.

Procedures are a kind of object.

Numbers are a kind of object.  (So far, every essential or
optional operation on numbers is generic, although some
operations have domain restrictions.)

Symbols are a kind of object.

Pairs are a kind of object.  Pairs are heterogenous mutable
records with two fields, known as the CAR and CDR fields.

Characters are a kind of object, but they need not be
distinguishable from certain other kinds of objects.  (This is to
allow characters to be implemented as small integers or as
strings of a single character.)

Strings are a kind of object.

Vectors are a kind of object.  Vectors are simple heterogenous
mutable structures indexed by integers, with 0 as the least
index.

[The question of whether streams should be a kind of object was
deferred to the I/O committee.]

----------------------------------------------------------------

			   Procedures


The unary predicate NULL? is true of the empty list and false of
everything else.

The unary procedure NOT returns a true value if its argument is
false and a false value if its argument is true.


The binary procedure APPLY takes a procedure f and a list l, and
returns the result of f applied to l (considered as a list of
arguments.)  Optionally, APPLY may be extended as described in
the T manual.

The unary procedure CALL-WITH-CURRENT-CONTINUATION takes a
procedure f, and applies f to an escape procedure of one argument
corresponding to the current continuation.  The escape procedure
has unlimited extent.


The unary predicate NUMBER? is true of numbers and false of
everything else.  The unary predicate INTEGER? is true of
integers and false of everything else.  Every integer is a
number.  (For the sake of stripped-down Scheme implementations
intended for systems programming, it is not essential that there
be numbers other than integers.  It is expected, however, that
almost all implementations will approximate the behavior of real
numbers as well as does the IEEE 32-bit floating-point standard,
and many implementations will do better through the use of
bignums, ratios, and whatnot.)

The binary procedures +, -, *, and / take two numbers and return
the sum, difference, product, and quotient of their arguments, or
at least the best approximation thereto that an implementation
can reasonably provide.  (Thus (/ 2 9) may return a ratio in one
implementation, a floating point number in another, and may even
return 0 in a minimal implementation that approximates all
numbers by integers.)  Optionally, they may be generalized to
arbitrary arity as in Common Lisp.  (Hence unary negation is
optional.)

Optionally, the unary procedures 1+ and -1+ take a number and
return its successor and predecessor, where the successor of x is
defined as x + 1 and the predecessor as x - 1.  (The names make
sense if read as infix notation.)

The binary procedures QUOTIENT and REMAINDER take two integers
and return the quotient and remainder.  The second argument must
not be zero.  Precisely:  if the two arguments are x and y, and x
= qy + r where q and r are integers, ry >= 0, and 0 <= abs(r) <
abs(y), then the quotient is q and the remainder is r.  [Did I
get this right?]

Optionally, the binary procedure MOD is as in Common Lisp.  [The
numbers committee should confirm this.]

The unary procedure ABS takes a number and returns its absolute
value.

Optionally, the binary procedure GCD takes two integers and
returns their greatest common divisor.  [Can one of the two
arguments be zero?  Can the arguments be negative?  Is the result
always positive?]

The binary procedures MIN and MAX take two numbers and return the
minimum and maximum.  Optionally, they may be generalized to
arity >= 1.

The unary procedure RANDOM takes a positive integer n and returns
a nonnegative integer less than n.  (The intent is that RANDOM
should implement a random number generator using a high quality
algorithm.)

The binary predicates =, =?, <, <?, >, >?, >=, >=?, <=, and <=?
take two numbers and return true iff the first argument bears the
named relationship to the second.  (Despite the convention that
the names of true predicates end with a question mark, some
people prefer these names without the question mark, hence the
redundant names.)

The unary predicates ZERO?, NEGATIVE?, and POSITIVE? take a
number and return true if the argument is zero, negative, and
positive.

EXPT takes two numbers x and y and returns x raised to the y-th
power.

Optionally, there exist numbers that are not integers.  (Almost
all implementations will support this option!)  If there are
numbers other than integers, then the following procedures must
be supported:

    (EXP x)	  returns e to the x-th power.
    (LOG x)	  returns the natural logarithm of x.
    (SQRT x)	  returns the square root of x.
    (SIN x)	  returns the sine of x, where x is in radians.
    (COS x)	  returns the cosine of x, where x is in radians.
    (TAN x)	  returns the tangent of x, where x is in radians.
    (ASIN x)	  returns the arcsine of x in radians.
    (ACOS x)	  returns the arccosine of x in radians.
    (ATAN y x)	  returns the arctangent of y/x in radians.
    (FLOOR x)	  returns the largest integer <= x.
    (CEILING x)   returns the least integer >= x.
    (TRUNCATE x)  returns the integer of the same sign as x whose
                  magnitude is greatest among all such integers
                  with magnitude less than the magnitude of x.
    (ROUND x)	  returns the integer nearest to x.
		  [Stable rounding?]

[The details of the above operations on numbers are to be
formulated by the numbers committee.  We expect to conform with
Common Lisp and APL in most respects.]


The binary predicate EQ? is the most discriminating of the
standard equivalence predicates.  It is true iff its arguments
are "iso-ontic".  That is, if there is any way at all for a user
to distinguish the two arguments, then EQ? will return false.
This specification would allow EQ? to return false in all cases,
however, so there is one more condition: if x is a bound
variable, then (EQ? x x) returns true.

The binary predicate EQV? is a slightly less discriminating
equivalence predicate that abstracts away from some of the
implementation idiosyncrasies associated with numbers.  It is true
iff its arguments are EQ? or both arguments are numbers having
the same numeric value.  (It is a mistake to ask if two numbers
are EQV? when one of the numbers has lost precision through
approximation, however, and there is no telling what the result
will be in such a case.) [EQV? is incompatible with T and MIT
Scheme because (EQV? "abc" "abc") can be false.  Was that
intended?]

The binary predicate EQUAL? is the least discriminating of the
standard equivalence predicates.  It is true of its arguments x
and y iff

        its arguments are EQV?
    or  both x and y are strings and are STRING-EQUAL?
    or  both x and y are pairs and their CARs and CDRs are EQUAL?
    or  both x and y are vectors of the same length and they are
        EQUAL? element-wise
    or  both x and y are of some other type and are EQUAL?
        component-wise in some reasonable sense.

EQUAL? may not terminate on some arguments.  (EQUAL? is a
blunderbuss of a predicate and should not be used when a less
liberal predicate will suffice.)


The unary predicate SYMBOL? is true iff its argument is a symbol.
The unary procedure SYMBOL->STRING takes a symbol as argument and
returns its name as a string.  The unary procedure STRING->SYMBOL
takes a string as argument and returns a symbol having the string
as its name.  (The result of STRING->SYMBOL is an interned
symbol, which is the only kind of symbol required by this
report.)  [This report defines no destructive operations on
symbols or strings, so there is now no compelling reason to
distinguish between a string and a copy thereof.]

Optionally, the unary procedure STRING->UNINTERNED-SYMBOL takes a
string and returns an uninterned symbol having the string as its
name.


The unary procedure PAIR? returns true iff its argument is a
pair.  (Scheme has traditionally had a predicate known as ATOM?,
but this predicate has been superseded by PAIR?)  [Pairs,
formerly known as conses or dotted pairs, may be
indistinguishable from vectors of length 2.]

The binary procedure CONS creates a pair whose CAR field is
initialized to the first argument and whose CDR field is
initialized to the second argument.  It is guaranteed that the
new pair is not EQ? to any existing object.  The n-ary procedure
LIST returns a freshly consed list of its arguments.  The unary
procedures CAR and CDR take a pair and return the contents of its
CAR or CDR field.  It is a mistake to apply CAR or CDR to any
object other than a pair, and some implementations will signal an
error if the mistake is made.  [This is incompatible with many if
not most Lisps.]  The binary procedures SET-CAR! and SET-CDR!
take a pair x as first argument and an object y as second
argument, and store y in the CAR or CDR field of x.  The value
returned by SET-CAR! and SET-CDR! is unspecified, and it is a
mistake to use it; some implementations may signal an error if
the value is used.  [This also is incompatible with many if not
most Lisps.]

The unary procedures

    CAAR    CADR    CDAR    CDDR    CAAAR   CAADR   CADAR   CADDR
    CDAAR   CDADR   CDDAR   CDDDR   CAAAAR  CAAADR  CAADAR  CAADDR
    CADAAR  CADADR  CADDAR  CADDDR  CDAAAR  CDAADR  CDADAR  CDADDR
    CDDAAR  CDDADR  CDDDAR  CDDDDR

are compositions of CAR and CDR, where for example CADDR is
(LAMBDA (X) (CAR (CDR (CDR X)))).

The following descriptions use the notion of a proper list.  The
set of proper lists is the smallest set satisfying:

    the empty list is a proper list
    a pair x whose CDR is a proper list is a proper list,
        provided (MEMQ x (CDR x)) is false.

The unary procedure LENGTH takes a proper list as argument, and
returns its length, defined as the least integer k such that CDR
composed with itself k times and applied to the argument yields
the empty list.

The binary procedure APPEND takes two proper lists as arguments.
It could be defined by

    (DEFINE APPEND
        (LAMBDA (X Y)
          (IF (NULL? X)
              Y
              (CONS (CAR X) (APPEND (CDR X) Y)))))

but while APPEND will return a result that is EQUAL? to the
result returned by the procedure coded above, and will do so
without side effects, there is no guarantee that APPEND will
create any new pairs.  (For example, if either argument to APPEND
is the empty list, then APPEND may simply return the other
argument without copying it.  For that matter, APPEND may copy
both arguments.)  Optionally, APPEND may be generalized to
arbitrary arity.

Optionally, APPEND! is like APPEND except that it may side effect
either or both of its arguments.

Optionally, REVERSE takes a proper list as argument and returns a
proper list containing the elements of the argument in reverse
order.  REVERSE could be defined by

    (DEFINE REVERSE
      (LETREC ((LOOP (LAMBDA (X Y)
                       (IF (NULL? X)
                           Y
                           (LOOP (CDR X) (CONS (CAR X) Y))))))
        (LAMBDA (X)
          (LOOP X '()))))

but while REVERSE will return a result that is EQUAL? to the
result returned by the procedure coded above, and will do so
without side effects, there is no guarantee that REVERSE will
create any new pairs.  (There is no need to create new pairs when
the argument to REVERSE has length 1, for example.)

Optionally, LIST-REF and LIST-TAIL take a list and a nonnegative
integer as arguments, and return the values returned by the
procedures defined below:

    (DEFINE LIST-REF
      (LAMBDA (X N)
        (CAR (LIST-TAIL X N))))

    (DEFINE LIST-TAIL
      (LAMBDA (X N)
        (IF (ZERO? N)
            X
            (LIST-TAIL (CDR X) (- N 1)))))

Optionally, LAST-PAIR takes a non-empty list and returns the
value returned by the procedure defined below:

    (DEFINE LAST-PAIR
      (LAMBDA (X)
        (IF (PAIR? (CDR X))
            (LAST-PAIR (CDR X))
            X)))

The binary procedures MEMQ, MEMV, and MEMBER take an object x and
a proper list y and return the first sub-list of y beginning with
an object that is EQ?, EQV?, or EQUAL? (respectively) to x. If no
such element of y exists, then MEMQ, MEMV, and MEMBER return
false.  (This is slightly incompatible with most Lisps, which
return the empty list instead of false; for now, of course, the
empty list must be false in Scheme.)  (The reason the names of
these procedures do not end with question marks is that they
return useful values rather than just true or false.)

The binary procedures ASSQ, ASSV, and ASSOC take an object x and
a proper list of pairs y and return the first element of y whose
CAR is EQ?, EQV?, or EQUAL? (respectively) to x.  If no such
element of y exists, the ASSQ, ASSV, and ASSOC return false. (See
notes for MEMQ, MEMV, and MEMBER above.)

The binary procedure MAPCAR takes a unary procedure and a proper
list and returns a list of the results obtained from applying the
procedure element-wise to the proper list.  (No order of
evaluation is specified.)  Optionally, MAPCAR may be generalized
to >= 2 arguments.

The binary procedure MAPC takes a unary procedure f and a proper
list x and applies f element-wise to x, in order from the first
element of x to the last.  The value returned by MAPC is not
specified, and it is a mistake to use it; some implementations
may signal an error if it is used.


The string procedures below have no side effects and are always
sensitive to case.  No collating sequence whatsoever is
specified.

The unary predicate STRING? is true iff its argument is a string.
The binary predicate STRING-EQUAL? takes two strings and returns
true iff the strings are the same length and have the same
characters in the same positions.  The binary predicate
STRING-LESS? is an irreflexive total ordering on strings.  The
binary procedure STRING-APPEND takes two strings and returns the
catenation of the two strings.  Optionally, STRING-APPEND may be
generalized to arbitrary arity.

The unary procedure LIST->STRING takes a list of characters and
returns a string composed of those characters in order.  The
unary procedure STRING->LIST is a two-sided inverse to
LIST->STRING so far as STRING-EQUAL? is concerned.

The unary procedure STRING-LENGTH takes a string s and returns
(LENGTH (STRING->LIST s)).  The binary procedure STRING-REF takes
a string s and a nonnegative integer n and returns
(LIST-REF (STRING->LIST s) n), where LIST-REF is the optional
procedure described above.


The unary predicate VECTOR? is true iff its argument is a vector.
The unary procedure MAKE-VECTOR takes a nonnegative integer n as
argument and returns an uninitialized vector of length n.
Optionally, MAKE-VECTOR can be a binary procedure as well, in
which case the second argument is an object to be stored in every
element of the newly created vector.

The n-ary procedure VECTOR returns a vector of its arguments, by
analogy with LIST.

The unary procedure LIST->VECTOR takes a proper list and returns
a vector whose elements are the elements of the list.  The unary
procedure VECTOR->LIST takes a vector and returns a proper list
of its elements.  [Should the result of either be guaranteed to
be a new object?  What about vectors of length 0?]  The binary
procedure VECTOR-REF takes a vector v and a nonnegative integer n
and returns element n of v, where the first element of v is
element 0.  The ternary procedure VECTOR-SET! takes a vector v, a
nonnegative integer n, and an object x, and stores x in element n
of v.  The value returned by VECTOR-SET! is not specified.  It is
a mistake to use it, and some implementations may signal an error
if it is used.  The unary procedure VECTOR-LENGTH takes a vector
v and returns the number of elements in v, which is one greater
than the largest index acceptable to VECTOR-REF and VECTOR-SET!
for v.  Optionally, VECTOR-FILL! takes a vector v and an object x
and stores x in every element of v.


Optionally, the unary procedure OBJECT-HASH takes an object and
associates an integer with that object, returning the object.
OBJECT-HASH must guarantee that objects that are not EQ? are
associated with distinct integers.  Optionally, OBJECT-UNHASH
takes an integer and returns the object associated with that
integer if there is one, returning false otherwise.  (OBJECT-HASH
and OBJECT-UNHASH can be implemented using association lists and
ASSQ, but the intent is that they be efficient hash functions for
objects.)