[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
/BALLOT/
- To: common-lisp at SU-AI
- Subject: /BALLOT/
- From: STEELE at CMU-20C
- Date: Tue, 05 Oct 1982 04:41:00 -0000
- Cc: b.steele at CMU-10A
?????????????????????????????????????????????????????????????????????????????
? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ?
? % ================================================================= % ?
? % = $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ = % ?
? % = $ +++++++++++++++++++++++++++++++++++++++++++++++++++++ $ = % ?
? % = $ + ############################################### + $ = % ?
? % = $ + # ///////////////////////////////////////// # + $ = % ?
? % = $ + # / The October 1982 Common LISP Ballot / # + $ = % ?
? % = $ + # ///////////////////////////////////////// # + $ = % ?
? % = $ + ############################################### + $ = % ?
? % = $ +++++++++++++++++++++++++++++++++++++++++++++++++++++ $ = % ?
? % = $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ = % ?
? % ================================================================= % ?
? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ?
?????????????????????????????????????????????????????????????????????????????
Here is what you have all been waiting for! I need an indication of
consensus or lack thereof on the issues that have been discussed by
network mail since the August 1982 meeting, particularly on those issues
that were deferred for proposal for which proposals have now been made.
There are 28 questions, each requiring only a one-letter answer. As always,
if you don't like any of the choices, answer "x". To make my life easier
by permitting mechanical collation of responses, please respond as follows:
(a) send a reply message to Guy.Steele @ CMU-10A.
(b) *PLEASE* be sure the string "/BALLOT/" is in the subject line,
as it is in this message (the double quotes, not the slashes,
are metasyntactic!).
(c) The very first non-blank line of your message should have
exactly 29 non-blank characters on it. The first should be a
tilde ("~") and the rest should be your votes.
You may put spaces between the letters to improve readability.
(d) Following the first non-blank line, place any remarks about
issues on which you voted "x".
Thank you for your help. I would appreciate response by Friday, October 8.
--Guy
1. How shall the case for a floating-point exponent specifier
output by PRINT and FORMAT be determined?
(a) upper case, for example 3.5E6
(b) lower case, for example 3.5e6
(c) a switch
(d) implementation-dependent
2. Shall we change the name SETF to be SET? (y) yes (n) no
3. Shall there be a type specifier QUOTE, such that (QUOTE x) = (MEMBER x)?
Then MEMBER can be eliminated; (MEMBER x y z) = (OR 'x 'y 'z). Also one can
write such things as (OR INTEGER 'FOO) instead of (OR INTEGER (MEMBER FOO)).
(y) yes (n) no
4. Shall MOON's proposal for LOAD keywords, revised as shown below, be used?
(y) yes (n) no
----------------------------------------------------------------
Date: Wed, 25 Aug 1982 18:01:00 -0000
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
[slightly revised]
Here is a revised proposal:
Keyword Default Meaning
:PACKAGE NIL NIL means use file's native package, non-NIL
is a package or name of package to load into.
:VERBOSE *LOAD-VERBOSE* T means print a message saying what file is
being loaded into which package.
:PRINT NIL T means print values of forms as they are evaluated.
:ERROR T T means handle errors normally; NIL means that
a file-not-found error should return NIL
rather than signalling an error. LOAD returns
the pathname (or truename??) of the file it
loaded otherwise.
:SET-DEFAULT-PATHNAME *LOAD-SET-DEFAULT-PATHNAME*
T means update the pathname default
for LOAD from the argument, NIL means don't.
:STREAM NIL Non-NIL means this is an open stream to be
loaded from. (In the Lisp machine, the
:CHARACTERS message to the stream is used to
determine whether it contains text or binary.)
The pathname argument is presumed to be associated
with the stream, in systems where that information
is needed.
The global variables' default values are implementation dependent, according
to local conventions, and may be set by particular users according to their
personal taste.
I left out keywords to allow using a different set of defaults from the normal
one and to allow explicit control over whether a text file or a binary file
is being loaded, since these don't really seem necessary. If we put them in,
the consistent names would be :DEFAULT-PATHNAME, :CHARACTERS, and :BINARY.
----------------------------------------------------------------
5. Shall closures over dynamic variables be removed from Common LISP?
(y) yes (n) no
6. Shall LOOP, as summarized below, be included in Common LISP?
(y) yes (n) no
----------------------------------------------------------------
Date: Thu, 26 Aug 1982 22:51:00 -0000
From: David A. Moon <MOON at MIT-MC>
Here is an extremely brief summary of the proposed new LOOP design, which
has not yet been finalized. Consult the writeup on LOOP in the Lisp
Machine manual or MIT LCS TM-169 for background information. Constructive
comments are very welcome, but please reply to BUG-LOOP at MIT-ML, not to
me personally.
(LOOP form form...) repeatedly evaluates the forms.
In general the body of a loop consists of a series of clauses. Each
clause is either: a series of one or more lists, which are forms to be
evaluated for effect, delimited by a symbol or the end of the loop; or
a clause-introducing symbol followed by idiosyncratic syntax for that
kind of clause. Symbols are compared with SAMEPNAMEP. Atoms other than
symbols are in error, except where a clause's idiosyncratic syntax permits.
1. Primary clauses
1.1 Iteration driving clauses
These clauses run a local variable through a series of values and/or
generate a test for when the iteration is complete.
REPEAT <count>
FOR/AS <var> ...
CYCLE <var> ...
I won't go into the full syntax here. Features include: setting
to values before starting/on the first iteration/on iterations after
the first; iterating through list elements/conses; iterating through
sequence elements, forwards or backwards, with or without sequence-type
declaration; iterating through arithmetic progressions. CYCLE reverts
to the beginning of the series when it runs out instead of terminating
the iteration.
It is also possible to control whether or not an end-test is generated
and whether there is a special epilogue only evaluated when an individual
end-test is triggered.
1.2 Prologue and Epilogue
INITIALLY form form... forms to be evaluated before starting, but
after binding local variables.
FINALLY form form... forms to be evaluated after finishing.
1.3 Delimiter
DO a sort of semicolon needed in odd situations to terminate a clause,
for example between an INITIALLY clause and body forms when no named
clause (e.g. an iteration-driving clause) intervenes.
We prefer this over parenthesization of clauses because of the
general philosophy that it is more important to make the simple cases
as readable as possible than to make micro-improvements in the
complicated cases.
1.4 Blockname
NAMED name Gives the block generated by LOOP a name so that
RETURN-FROM may be used.
This will be changed to conform with whatever is put into Common Lisp
for named PROGs and DOs, if necessary.
2. Relevant special forms
The following special forms are useful inside the body of a LOOP. Note
that they need not appear at top level, but may be nested inside other
Lisp forms, most usefully bindings and conditionals.
(COLLECT <value> [USING <collection-mode>] [INTO <var>] [BACKWARDS]
[FROM <initial-value>] [IF-NONE <expr>] [[TYPE] <type>])
This special form signals an error if not used lexically inside a LOOP.
Each time it is evaluated, <value> is evaluated and accumulated in a way
controlled by <collection-mode>; the default is to form an ordered list.
The accumulated values are returned from the LOOP if it is finished
normally, unless INTO is used to put them into a variable (which gets
bound locally to the LOOP). Certain accumulation modes (boolean AND and
OR) cause immediate termination of the LOOP as soon as the result is known,
when not collecting into a variable.
Collection modes are extensible by the user. A brief summary of predefined
ones includes aggregated boolean tests; lists (both element-by-element and
segment-by-segment); commutative/associative arithmetic operators (plus,
times, max, min, gcd, lcm, count); sets (union, intersection, adjoin);
forming a sequence (array, string).
Multiple COLLECT forms may appear in a single loop; they are checked for
compatibility (the return value cannot both be a list of values and a
sum of numbers, for example).
(RETURN value) returns immediately from a LOOP, as from any other block.
RETURN-FROM works too, of course.
(LOOP-FINISH) terminates the LOOP, executing the epilogue and returning
any value defined by a COLLECT special form.
[Should RESTART be interfaced to LOOP, or only be legal for plain blocks?]
3. Secondary clauses
These clauses are useful abbreviations for things that can also be done
using the primary clauses and Lisp special forms. They exist to make
simple cases more readable. As a matter of style, their use is strongly
discouraged in complex cases, especially those involving complex or
nested conditionals.
3.1 End tests
WHILE <expr> (IF (NOT <expr>) (LOOP-FINISH))
UNTIL <expr> (IF <expr> (LOOP-FINISH))
3.2 Conditionals
WHEN <expr> <clause> The clause is performed conditionally.
IF <expr> <clause> synonymous with WHEN
UNLESS <expr> <clause> opposite of WHEN
AND <clause> May be suffixed to a conditional. These two
ELSE <clause> might be flushed as over-complex.
3.3 Bindings
WITH <var> ... Equivalent to wrapping LET around the LOOP.
This exists to promote readability by decreasing
indentation.
3.4 Return values
RETURN <expr> synonymous with (RETURN <expr>)
COLLECT ... synonymous with (COLLECT ...)
NCONC ... synonymous with (COLLECT ... USING NCONC)
APPEND, SUM, COUNT, MINIMIZE, etc. are analogous
ALWAYS, NEVER, THEREIS abbreviations for boolean collection
4. Extensibility
There are ways for users to define new iteration driving clauses which
I will not go into here. The syntax is more flexible than the existing
path mechanism.
There are also ways to define new kinds of collection.
5. Compatibility
The second generation LOOP will accept most first-generation LOOP forms
and execute them in the same way, although this was not a primary goal.
Some complex (and unreadable!) forms will not execute the same way or
will be errors.
6. Documentation
We intend to come up with much better examples. Examples are very
important for developing a sense of style, which is really what LOOP
is all about.
----------------------------------------------------------------
7. Regardless of the outcome of the previous question, shall CYCLE
be retained and be renamed LOOP, with the understanding that statements
of the construct must be non-atomic, and atoms as "statements" are
reserved for extensions, and any such extensions must be compatible
with the basic mening as a pure iteration construct?
(y) yes (n) no
8. Shall ARRAY-DIMENSION be changed by exchanging its arguments,
to have the array first and the axis number second, to parallel
other indexing operations?
(y) yes (n) no
9. Shall MACROEXPAND, as described below, replace the current definition?
(y) yes (n) no
----------------------------------------------------------------
Date: Mon, 30 Aug 1982 01:26:00 -0000
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Here is my promised proposal, with some help from Alan.
MACRO-P becomes a predicate rather than a pseudo-predicate.
Everything on pages 92-93 (29July82) is flushed.
Everything, including the compiler, expands macros by calling MACROEXPAND
or MACROEXPAND-1. A variable, *MACROEXPAND-HOOK*, is provided to allow
implementation of displacing, memoization, etc.
The easiest way to show the details of the proposal is as code. I'll try to
make it exemplary.
(DEFVAR *MACROEXPAND-HOOK* 'FUNCALL)
(DEFUN MACROEXPAND (FORM &AUX CHANGED)
"Keep expanding the form until it is not a macro-invocation"
(LOOP (MULTIPLE-VALUE (FORM CHANGED) (MACROEXPAND-1 FORM))
(IF (NOT CHANGED) (RETURN FORM))))
(DEFUN MACROEXPAND-1 (FORM)
"If the form is a macro-invocation, return the expanded form and T.
This is the only function that is allowed to call macro expander functions.
*MACROEXPAND-HOOK* is used to allow memoization."
(DECLARE (VALUES FORM CHANGED-FLAG))
(COND ((AND (PAIRP FORM) (SYMBOLP (CAR FORM)) (MACRO-P (CAR FORM)))
(LET ((EXPANDER (---get expander function--- (CAR FORM))))
---check for wrong number of arguments---
(VALUES (FUNCALL *MACROEXPAND-HOOK* EXPANDER FORM) T)))
(T FORM)))
;You can set *MACROEXPAND-HOOK* to this to get traditional displacing
(DEFUN DISPLACING-MACROEXPAND-HOOK (EXPANDER FORM)
(LET ((NEW-FORM (FUNCALL EXPANDER FORM)))
(IF (ATOM NEW-FORM)
(SETQ NEW-FORM `(PROGN ,NEW-FORM)))
(RPLACA FORM (CAR NEW-FORM))
(RPLACD FORM (CDR NEW-FORM))
FORM))
The above definition of MACROEXPAND-1 is oversimplified, since it can
also expand other things, including lambda-macros (the subject of a separate
proposal that has not been sent yet) and possibly implementation-dependent
things (substs in the Lisp machine, for example).
The important point here is the division of labor. MACROEXPAND-1 takes care
of checking the length of the macro-invocation to make sure it has the right
number of arguments [actually, the implementation is free to choose how much
of this is done by MACROEXPAND-1 and how much is done by code inserted into
the expander function by DEFMACRO]. The hook takes care of memoization. The
macro expander function is only concerned with translating one form into
another, not with bookkeeping. It is reasonable for certain kinds of
program-manipulation programs to bind the hook variable.
I introduced a second value from MACROEXPAND-1 instead of making MACROEXPAND
use the traditional EQ test. Otherwise a subtle change would have been
required to DISPLACING-MACROEXPAND-HOOK, and some writers of hooks might get
it wrong occasionally, and their code would still work 90% of the time.
Other issues:
On page 93 it says that MACROEXPAND ignores local macros established by
MACROLET. This is clearly incorrect; MACROEXPAND has to get called with an
appropriate lexical context available to it in the same way that EVAL does.
They are both parts of the interpreter. I don't have anything to propose
about this now; I just want to point out that there is an issue. I don't
think we need to deal with the issue immediately.
A related issue that must be brought up is whether the Common Lisp subset
should include primitives for accessing and storing macro-expansion
functions. Currently there is only a special form (MACRO) to set a
macro-expander, and no corresponding function. The Lisp machine expedient of
using the normal function-definition primitive (FDEFINE) with an argument of
(MACRO . expander) doesn't work in Common Lisp. Currently there is a gross
way to get the macro expander function, but no reasonable way. I don't have
a clear feeling whether there are programs that would otherwise be portable
except that they need these operations.
----------------------------------------------------------------
10. Shall all global system-defined variables have names beginning
and ending with "*", for example *PRINLEVEL* instead of PRINLEVEL
and *READ-DEFAULT-FLOAT-FORMAT* instead of READ_DEFAULT-FLOAT-FORMAT?
(y) yes (n) no
11. Same question for named constants (other than T and NIL), such as
*PI* for PI and *MOST-POSITIVE-FIXNUM* for MOST-POSITIVE-FIXNUM.
(y) yes (n) no (o) yes, but use a character other than "*"
12. Shall a checking form CHECK-TYPE be introduced as described below?
(y) yes (n) no
----------------------------------------------------------------
Date: Thu, 26 Aug 1982 07:04:00 -0000
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
See p.275 of the 29 July Common Lisp manual and p.275 of the revision
handed out at the Lisp conference.
I suggest that we include CHECK-ARG-TYPE in the language. Although
CHECK-ARG, CHECK-ARG-TYPE, and ASSERT have partially-overlapping
functionality, each has its own valuable uses and I think all three
ought to be in the language.
Note that CHECK-ARG and CHECK-ARG-TYPE are used when you want explicit
run-time checking, including but not limited to writing the interpreter
(which of course is written in Lisp, not machine language!).
The details:
CHECK-ARG-TYPE arg-name type &OPTIONAL type-string [macro]
If (TYPEP arg-name 'type) is false, signal an error. The error message
includes arg-name and a "pretty" English-language form of type, which
can be overridden by specifying type-string (this override is rarely
used). Proceeding from the error sets arg-name to a new value and
makes the test again.
Currently arg-name must be a variable, but it should be generalized to
any SETF'able place.
type and type-string are not evaluated.
This isn't always used for checking arguments, since the value of any
variable can be checked, but it is usually used for arguments and there
isn't an alternate name that more clearly describes what it does.
Date: Thu, 02 Sep 1982 16:30:00 -0000
From: JonL at PARC-MAXC
PDP10 MacLisp and VAX/NIL have had the name CHECK-TYPE for several
years for essentially this functionality (unless someone has recently renamed
it). Since it is used to certify the type of any variable's value, it did not
include the "-ARG" part. The motivation was to have a "checker" which was
more succinct than CHECK-ARGS, but which would generally open-code the
type test (and hence introduce no delay to the non-error case).
I rather prefer the semantics you suggested, namely that the second argument
to CHECK-TYPE be a type name (given the CommonLisp treatment of type
hierarchy). At some level, I'd think a "promise" of fast type checking should
be guaranteed (in compiled code) so that persons will prefer to use this
standardized facililty; without some indication of performance, one would
be tempted to write his own in order not to slow down the common case.
----------------------------------------------------------------
13. Shall a checking form CHECK-SUBSEQUENCE be introduced as described below?
(y) yes (n) no
----------------------------------------------------------------
Date: Thu, 02 Sep 1982 16:30:00 -0000
From: JonL at PARC-MAXC
If the general sequence functions continue to thrive in CommonLisp, I'd
like to suggest that the corresponding CHECK-SUBSEQUENCE macro (or
whatever renaming of it should occur) be included in CommonLisp.
CHECK-SUBSEQUENCE (<var> <start-index> <count>) &optional <typename>)
provides a way to certify that <var> holds a sequence datum of the type
<typename>, or of any suitable sequence type (e.g., LIST, or STRING or
VECTOR etc) if <typename> is null; and that the indicated subsequence
in it is within the size limits.
[GLS: probably <end> is more appropriate than <count> for Common LISP.]
----------------------------------------------------------------
14. Shall the functions LINE-OUT and STRING-OUT, eliminated in November,
be reinstated?
(y) yes (n) no
15. Shall the REDUCE function be added as described below?
(y) yes (n) no
----------------------------------------------------------------
Date: Fri, 03 Sep 1982 21:56:00 -0000
From: Guy.Steele at CMU-10A
I would like to mildly re-propose the REDUCE function for Common
LISP, now that adding it would require only one new function, not ten
or fifteen:
REDUCE function sequence &KEY :START :END :FROM-END :INITIAL-VALUE
The specified subsequence of "sequence" is reduced, using the "function"
of two arguments. The reduction is left-associative, unless
:FROM-END is not false, in which case it is right-associative.
If the an :INITIAL-VALUE is given, it is logically placed before the
"sequence" (after it if :FROM-END is true) and included in the
reduction operation. If no :INITIAL-VALUE is given, then the "sequence"
must not be empty. (An alternative specification: if no :INITIAL-VALUE
is given, and "sequence" is empty, then "function" is called with
zero arguments and the result returned. How about that? This idea
courtesy of Dave Touretzky.)
(REDUCE #'+ '(1 2 3 4)) => 10
(REDUCE #'- '(1 2 3 4)) => -8
(REDUCE #'- '(1 2 3 4) :FROM-END T) => -2 ;APL-style
(REDUCE #'LIST '(1 2 3 4)) => (((1 2) 3) 4)
(REDUCE #'LIST '(1 2 3 4) :FROM-END T) => (1 (2 (3 4)))
(REDUCE #'LIST '(1 2 3 4) :INITIAL-VALUE 'FOO) => ((((FOO 1) 2) 3) 4)
(REDUCE #'LIST '(1 2 3 4) :FROM-END T :INITIAL-VALUE 'FOO)
=> (1 (2 (3 (4 FOO))))
----------------------------------------------------------------
16. Shall the Bawden/Moon solution to the "invisible block" problem
be accepted? The solution is to define (RETURN x) to mean precisely
(RETURN-FROM NIL x), and to specify that essentially all standard
iterators produce blocks named NIL. A block with a name other than
NIL cannot capture a RETURN, only a RETURN-FROM with a matching name.
(y) yes (n) no
17. Shall the TAGBODY construct be incorporated? This expresses just
the behavior of the GO aspect of a PROG. Any atoms in the body
are not evaluated, but serve as tags that may be specified to GO.
Tags have lexical scope and dynamic extent. TAGBODY always returns NIL.
(y) yes (n) no
18. What shall be done about RESTART? The following alternatives seem to
be the most popular:
(a) Have no RESTART form.
(b) RESTART takes the name of a block. What happens when you say
(RESTART NIL) must be clarified for most iteration constructs.
(c) There is a new binding form called, say, RESTARTABLE.
Within (RESTARTABLE FOO . body), (RESTART FOO) acts as a jump
to the top of the body of the enclosing, matching RESTARTABLE form.
RESTART tags have lexical scope and dynamic extent.
19. Shall there be a built-in identity function, and if so, what shall it
be called?
(c) CR (i) IDENTITY (n) no such function
20. Shall the #*... bit-string syntax replace #"..."? That is, shall what
was before written #"10010" now be written #*10010 ?
(y) yes (n) no
21. Which of the two outstanding array proposals (below) shall be adopted?
(s) the "simple" proposal
(r) the "RPG memorial" proposal
(m) the "simple" proposal as amended by Moon
----------------------------------------------------------------
*********** "Simple" proposal **********
Date: Fri, 17 Sep 1982 03:27:00 -0000
From: Scott E. Fahlman <Fahlman at Cmu-20c>
Here is a revision of my array proposal, fixed up in response to some of
the feedback I've received. See if you like it any better than the
original. In particular, I have explictly indicated that certain
redundant forms such as MAKE-VECTOR should be retained, and I have
removed the :PRINT keyword, since I now believe that it causes more
trouble than it is worth. A revised printing proposal appears at the
end of the document.
Arrays can be 1-D or multi-D. All arrays can be created by MAKE-ARRAY
and can be accessed with AREF. Storage is done via SETF of an AREF.
The term VECTOR refers to any array of exactly one dimension.
Vectors are special, in that they are also sequences, and can be
referenced by ELT. Also, only vectors can have fill pointers.
Vectors can be specialized along several distinct axes. The first is by
the type of the elements, as specified by the :ELEMENT-TYPE keyword to
MAKE-ARRAY. A vector whose element-type is STRING-CHAR is referred to
as a STRING. Strings, when they print, use the "..." syntax; they also
are the legal inputs to a family of string-functions, as defined in the
manual. A vector whose element-type is BIT (alias (MOD 2)), is a
BIT-VECTOR. These are special because they form the set of legal inputs
to the boolean bit-vector functions. (We might also want to print them
in a strange way -- see below.)
Some implementations may provide a special, highly efficient
representation for simple vectors. A simple vector is (of course) 1-D,
cannot have a fill pointer, cannot be displaced, and cannot be altered
in size after its creation. To get a simple vector, you use the :SIMPLE
keyword to MAKE-ARRAY with a non-null value. If there are any
conflicting options specified, an error is signalled. If an
implementation does not support simple vectors, this keyword/value is
ignored except that the error is still signalled on inconsistent cases.
We need a new set of type specifiers for simple things: SIMPLE-VECTOR,
SIMPLE-STRING, and SIMPLE-BIT-VECTOR, with the corresponding
type-predicate functions. Simple vectors are referenced by AREF in the
usual way, but the user may use THE or DECLARE to indicate at
compile-time that the argument is simple, with a corresponding increase
in efficiency. Implementations that do not support simple vectors
ignore the "simple" part of these declarations.
Strings (simple or non-simple) self-eval; all other arrays cause an
error when passed to EVAL. EQUAL descends into strings, but not
into any other arrays. EQUALP descends into arrays of all kinds,
comparing the corresponding elements with EQUALP. EQUALP is false
if the array dimensions are not the same, but it is not sensitive to
the element-type of the array, whether it is simple, etc. In comparing
the dimensions of vectors, EQUALP uses the length from 0 to the fill
pointer; it does not look at any elements beyond the fill pointer.
The set of type-specifiers required for all of this is ARRAY, VECTOR,
STRING, BIT-VECTOR, SIMPLE-VECTOR, SIMPLE-STRING, SIMPLE-BIT-VECTOR.
Each of these has a corresponding type-P predicate, and each can be
specified in list from, along with the element-type and dimension(s).
MAKE-ARRAY takes the following keywords: :ELEMENT-TYPE, :INITIAL-VALUE,
:INITIAL-CONTENTS, :FILL-POINTER, and :SIMPLE. There is still some
discussion as to whether we should retain array displacement, which
requires :DISPLACED-TO and :DISPLACED-INDEX-OFFSET.
The following functions are redundant, but should be retained for
clarity and emphasis in code: MAKE-VECTOR, MAKE-STRING, MAKE-BIT-VECTOR.
MAKE-VECTOR takes the same keywords as MAKE-ARRAY, but can only take a
single integer as the dimension argument. MAKE-STRING and
MAKE-BIT-VECTOR are like MAKE-VECTOR, but do not take the :ELEMENT-TYPE
keyword, since the element-type is implicit. Similarly, we should
retain the forms VREF, CHAR, and BIT, which are identical in operation
to AREF, but which declare their aray argument to be VECTOR, STRING, or
BIT-VECTOR, respectively.
If the :SIMPLE keyword is not specified to MAKE-ARRAY or related forms,
the default is NIL. However, vectors produced by random forms such as
CONCATENATE are simple, and vectors created when the reader sees #(...)
or "..." are also simple.
As a general rule, arrays are printed in a simple format that, upon
being read back in, produces a form that is EQUALP to the original.
However, some information may be lost in the printing process:
element-type restrictions, whether a vector is simple, whether it has a
fill pointer, whether it is displaced, and the identity of any element
that lies beyond the fill pointer. This choice was made to favor ease
of interactive use; if the user really wants to preserve in printed form
some complex data structure containing non-simple arrays, he will have
to develop his own printer.
A switch, SUPPRESS-ARRAY-PRINTING, is provided for users who have lots
of large arrays around and don't want to see them trying to print. If
non-null, this switch causes all arrays except strings to print in a
short, non-readable form that does not include the elements:
#<array-...>. In addition, the printing of arrays and vectors (but not
of strings) is subject to PRINLEVEL and PRINLENGTH.
Strings, simple or otherwise, print using the "..." syntax. Upon
read-in, the "..." syntax creates a simple string.
Bit-vectors, simple or otherwise, print using the #"101010..." syntax.
Upon read-in, this format produces a simple bit-vector. Bit vectors do
observe SUPPRESS-ARRAY-PRINTING.
All other vectors print out using the #(...) syntax, observing
PRINLEVEL, PRINLENGTH, and SUPPRESS-ARRAY-PRINTING. This format reads
in as a simple vector of element-type T.
All other arrays print out using the syntax #nA(...), where n is the
number of dimensions and the list is a nest of sublists n levels deep,
with the array elements at the deepest level. This form observes
PRINLEVEL, PRINLENGTH, and SUPPRESS-ARRAY-PRINTING. This format reads
in as an array of element-type T.
Query: I am still a bit uneasy about the funny string-like syntax for
bit vectors. Clearly we need some way to read these in that does not
turn into a type-T vector. An alternative might be to allow #(...) to
be a vector of element-type T, as it is now, but to take the #n(...)
syntax to mean a vector of element-type (MOD n). A bit-vector would
then be #2(1 0 1 0...) and we would have a parallel notation available
for byte vectors, 32-bit word vectors, etc. The use of the #n(...)
syntax to indicate the length of the vector always struck me as a bit
useless anyway. One flaw in this scheme is that it does not extend to
multi-D arrays. Before someone suggests it, let me say that I don't
like #nAm(...), where n is the rank and m is the element-type -- it
would be too hard to remember which number was which. But even with
this flaw, the #n(...) syntax might be useful.
********** "RPG memorial" proposal **********
Date: Thu, 23 Sep 1982 04:38:00 -0000
From: Scott E. Fahlman <Fahlman at Cmu-20c>
Several people have stated that they dislike my earlier proposal because
it uses the good names (VECTOR, STRING, BIT-VECTOR, VREF, CHAR, BIT) on
general 1-D arrays, and makes the user say "simple" when he wants one of
the more specialized high-efficiency versions. This makes extra work
for users, who will want simple vectors at least 95% of the time. In
addition, there is the argument that simple vectors should be thought of
as a first-class data-type (in implementations that provide them) and
not as a mere degenerate form of array.
Just to see what it looks like, I have re-worked the earlier proposal to
give the good names to the simple forms. This does not really eliminate
any of the classes in the earlier proposal, since each of those classes
had some attributes or operations that distinguished it from the others.
Since there are getting to be a lot of proposals around, we need some
nomencalture for future discussions. My first attempt, with the
user-settable :PRINT option should be called the "print-switch"
proposal; the next one, with the heavy use of the :SIMPLE switch should
be the "simple-switch" proposal; this one can be called the "RPG
memorial" proposal. Let me know what you think about this vs. the
simple-switch version -- I can live with either, but I really would like
to nail this down pretty soon so that we can get on with the
implementation.
Arrays can be 1-D or multi-D. All arrays can be created by MAKE-ARRAY
and can be accessed with AREF. Storage is done via SETF of an AREF.
1-D arrays are special, in that they are also of type SEQUENCE, and can
be referenced by ELT. Also, only 1-D arrays can have fill pointers.
Some implementations may provide a special, highly efficient
representation for simple 1-D arrays, which will be of type VECTOR. A
vector is 1-dimensional, cannot have a fill pointer, cannot be
displaced, and cannot be altered in size after its creation. To get a
vector, you use the :VECTOR keyword to MAKE-ARRAY with a non-null value.
If there are any conflicting options specified, an error is signalled.
The MAKE-VECTOR form is equivalent to MAKE-ARRAY with :VECTOR T.
A STRING is a VECTOR whose element-type (specified by the :ELEMENT-TYPE
keyword) is STRING-CHAR. Strings are special in that they print using
the "..." syntax, and they are legal inputs to a class of "string
functions". Actually, these functions accept any 1-D array whose
element type is STRING-CHAR. This more general class is called a
CHAR-SEQUENCE.
A BIT-VECTOR is a VECTOR whose element-type is BIT, alias (MOD 2).
Bit-vectors are special in that they print using the #*... syntax, and
they are legal inputs to a class of boolean bit-vector functions.
Actually, these functions accept any 1-D array whose element-type is
BIT. This more general class is called a BIT-SEQUENCE.
All arrays can be referenced via AREF, but in some implementations
additional efficiency can be obtained by declaring certain objects to be
vectors, strings, or bit-vectors. This can be done by normal
type-declarations or by special accessing forms. The form (VREF v n) is
equivalent to (AREF (THE VECTOR v) n). The form (CHAR s n) is
equivalent to (AREF (THE STRING s) n). The form (BIT b n) is equivalent
to (AREF (THE BIT-VECTOR b) n).
If an implementation does not support vectors, the :VECTOR keyword is
ignored except that the error is still signalled on inconsistent cases;
The additional restrictions on vectors are not enforced. MAKE-VECTOR is
treated just like the equivalent make-array. VECTORP is true of every
1-D array, STRINGP of every CHAR-SEQUENCE, and BIT-VECTOR of every
BIT-SEQUENCE.
CHAR-SEQUENCEs, including strings, self-eval; all other arrays cause an
error when passed to EVAL. EQUAL descends into CHAR-SEQUENCEs, but not into
any other arrays. EQUALP descends into arrays of all kinds, comparing
the corresponding elements with EQUALP. EQUALP is false if the array
dimensions are not the same, but it is not sensitive to the element-type
of the array, whether it is a vector, etc. In comparing the dimensions of
vectors, EQUALP uses the length from 0 to the fill pointer; it does not
look at any elements beyond the fill pointer.
The set of type-specifiers required for all of this is ARRAY, VECTOR,
STRING, BIT-VECTOR, SEQUENCE, CHAR-SEQUENCE, and BIT-SEQUENCE.
Each of these has a corresponding type-P predicate, and each can be
specified in list from, along with the element-type and dimension(s).
MAKE-ARRAY takes the following keywords: :ELEMENT-TYPE, :INITIAL-VALUE,
:INITIAL-CONTENTS, :FILL-POINTER, :DISPLACED-TO, :DISPLACED-INDEX-OFFSET,
and :VECTOR.
The following functions are redundant, but should be retained for
clarity and emphasis in code: MAKE-VECTOR, MAKE-STRING, MAKE-BIT-VECTOR.
MAKE-VECTOR takes a single length argument, along with :ELEMENT-TYPE,
:INITIAL-VALUE, and :INITIAL-CONTENTS. MAKE-STRING and MAKE-BIT-VECTOR
are like MAKE-VECTOR, but do not take the :ELEMENT-TYPE keyword, since
the element-type is implicit.
If the :VECTOR keyword is not specified to MAKE-ARRAY or related forms,
the default is NIL. However, sequences produced by random forms such as
CONCATENATE are vectors.
Strings always are printed using the "..." syntax. Bit-vectors always
are printed using the #*... syntax. Other vectors always print using
the #(...) syntax. Note that in the latter case, any element-type
restriction is lost upon readin, since this form always produces a
vector of type T when it is read. However, the new vector will be
EQUALP to the old one. The #(...) syntax observes PRINLEVEL,
PRINLENGTH, and SUPPRESS-ARRAY-PRINTING. The latter switch, if non-NIL,
causes the array to print in a non-readable form: #<ARRAY...>.
CHAR-SEQUENCEs print out as though they were strings, using the "..."
syntax. BIT-SEQUENCES print out as BIT-STRINGS, using the #*... syntax.
All other arrays print out using the #nA(...) syntax, where n is the
number of dimensions and the list is actually a list of lists of lists,
nested n levels deep. The array elements appear at the lowest level.
The #A syntax also observes PRINLEVEL, PRINLENGTH, and
SUPPRESS-ARRAY-PRINTING. The #A format reads in as a non-displaced
array of element-type T.
Note that when an array is printed and read back in, the new version is
EQUALP to the original, but some information about the original is lost:
whether the original was a vector or not, element type restrictions,
whether the array was displaced, whether there was a fill pointer, and
the identity of any elements beyond the fill-pointer. This choice was
made to favor ease of interactive use; if the user really wants to
preserve in printed form some complex data structure containing more
complex arrays, he will have to develop his own print format and printer.
********** Moon revision of "simple" proposal **********
Date: Thu, 30 Sep 1982 05:59:00 -0000
From: MOON at SCRC-TENEX
I prefer the "simple switch" to the "RPG memorial" proposal, with one
modification to be found below. The reason for this preference is that
it makes the "good" name, STRING for example, refer to the general class
of objects, relegating the efficiency decision to a modifier ("simple").
The alternative makes the efficiency issue too visible to the casual user,
in my opinion. You have to always be thinking "do I only want this to
work for efficient strings, which are called strings, or should it work
for all kinds of strings, which are called arrays of characters?".
Better to say, "well this works for strings, and hmm, is it worth
restricting it to simple-strings to squeeze out maximal efficiency"?
Lest this seem like I am trying to sabotage the efficiency of Lisp
implementations that are stuck with "stock" hardware, consider the
following:
In the simple switch proposal, how is (MAKE-ARRAY 100) different from
(MAKE-ARRAY 100 :SIMPLE T)? In fact, there is only one difference--it is
an error to use ADJUST-ARRAY-SIZE on the latter array, but not on the
former. Except for this, simpleness consists, simply, of the absence of
options. This suggests to me that the :SIMPLE option be flushed, and
instead a :ADJUSTABLE-SIZE option be added (see, I pronounce the colons).
Even on the Lisp machine, where :ADJUSTABLE-SIZE makes no difference, I
think it would be an improvement, merely for documentation purposes. Now
everything makes sense: if you don't ask for any special features in your
arrays, you get simple ones, which is consistent with the behavior of the
sequence functions returning simple arrays always. And if some
implementation decides they need the sequence functions to return
non-simple arrays, they can always add additional keywords to them to so
specify. The only time you need to know about the word "simple" at all is
if you are making type declarations for efficiency, in which case you have
to decide whether to declare something to be a STRING or a SIMPLE-STRING.
And it makes sense that the more restrictive declaration be a longer word.
This also meets RPG's objection, which I think boils down to the fact
that he thought it was stupid to have :SIMPLE T all over his programs.
He was right.
I'm fairly sure that I don't understand the portability issues that KMP
brought up (I don't have a whole lot of time to devote to this). But I
think that in my proposal STRINGP and SIMPLE-STRINGP are never the same
in any implementation; for instance, in the Lisp machine STRINGP is true
of all strings, while SIMPLE-STRINGP is only true of those that do not
have fill-pointers. If we want to legislate that the :ADJUSTABLE-SIZE
option is guaranteed to turn off SIMPLE-STRINGP, I expect I can dig up
a bit somewhere to remember the value of the option. This would in fact
mean that simple-ness is a completely implementation-independent concept,
and the only implementation-dependence is how much (if any) efficiency
you gain by using it, and how much of that efficiency you get for free
and how much you get only if you make declarations.
Perhaps the last sentence isn't obvious to everyone. On the LM-2 Lisp
machine, a simple string is faster than a non-simple string for many
operations. This speed-up happens regardless of declarations; it is a
result of a run-time dispatch to either fast microcode or slow microcode.
On the VAX with a dumb compiler and no tuning, a simple string is only
faster if you make declarations. On the VAX with a dumb compiler but some
obvious tuning of sequence and string primitives to move type checks out of
inner loops (making multiple copies of the inner loop), simple strings are
faster for these operations, but still slow for AREF unless you make a type
declaration. On the VAX with a medium-smart compiler that does the same
sort of tuning on user functions, simple strings are faster for user
functions, too, if you only declare (OPTIMIZE SPEED) [assuming that the
compiler prefers space over speed by default, which is the right choice in
most implementations], and save space as well as time if you go whole hog
and make a type declaration. On the 3600 Lisp machine, you have sort of a
combination of the first case and the last case.
I also support the #* syntax for bit vectors, rather than the #" syntax.
It's probably mere temporal accident that the simple switch proposal
uses #" while the RPG memorial proposal uses #*.
To sum up:
A vector is a 1-dimensional array. It prints as #(foo bar) or #<array...>
depending on the value of a switch.
A string is a vector of characters. It always prints as "foo". Unlike
all other arrays, strings self-evaluate and are compared by EQUAL.
A bit-vector is a vector of bits. It always prints as #*101. Since as
far as I can tell these are redundant with integers, perhaps like integers
they should self-evaluate and be compared by EQUAL. I don't care.
A simple-vector, simple-string, or simple-bit-vector is one of the above
with none of the following MAKE-ARRAY (or MAKE-STRING) options specified:
:FILL-POINTER
:ADJUSTABLE-SIZE
:DISPLACED-TO
:LEADER-LENGTH, :LEADER-LIST (in implementations that offer them)
There are type names and predicates for the three simple array types. In
some implementations using the type declaration gets you more efficient
code that only works for that simple type, which is why these are in the
language at all. There are no user-visible distinctions associated with
simpleness other than those implied by the absence of the above MAKE-ARRAY
options.
----------------------------------------------------------------
22. Shall the following proposal for the OPTIMIZE declaration be adopted?
(y) yes (n) no
----------------------------------------------------------------
Date: Thu, 16 Sep 1982 00:51:00 -0000
From: Scott E. Fahlman <Fahlman at Cmu-20c>
At the meeting I volunteered to produce a new proposal for the OPTIMIZE
declaration. Actually, I sent out such a proposal a couple of weeks
ago, but somehow it got lost before reaching SU-AI -- both that machine
and CMUC have been pretty flaky lately. I did not realize that the rest
of you had not seen this proposal until a couple of days ago.
Naturally, this is the one thing I did not keep a copy of, so here is my
reconstruction. I should say that this proposal is pretty ugly, but it
is the best that I've been able to come up with. If anyone out there
can do better, feel free.
Guy originally proposed a format like (DECLARE (OPTIMIZE q1 q2 q3)),
where each of the q's is a quality from the set {SIZE, SPEED, SAFETY}.
(He later suggested to me that COMPILATION-SPEED would be a useful
fourth quality.) The ordering of the qualities tells the system which
to optimize for. The obvious problem is that you sometimes want to go
for, say, SPEED above all else, but usually you want some level of
compromise. There is no way in this scheme to specify how strongly the
system should favor one quality over another. We don't need a lot of
gradations for most compilers, but the simple ordering is not expressive
enough.
One possibility is to simply reserve the OPTIMIZE declaration for the
various implementations, but not to specify what is done with it. Then
the implementor could specify in the red pages whatever declaration
scheme his compiler wants to follow. Unfortunately, this means that
such declarations would be of no use when the code is ported to another
Common Lisp, and users would have no portable way to flag that some
function is an inner loop and should be super-fast, or whatever. The
proposal below tries to provide a crude but adequate optimization
declaration for portable code, while still making it possible for users
to fine-tune the compiler's actions for particular implementations.
What I propose is (DECLARE (OPTIMIZE (qual1 value1) (qual2 value2) ...),
where the qualities are the four mentioned above and each is paired with
a value from 0 to 3 inclusive. The ordering of the clauses doesn't
matter, and any quality not specified gets a default value of 1. The
intent is that {1, 1, 1, 1} would be the compiler's normal default --
whatever set of compromises the implementor believes is appropriate for
his user community. A setting of 0 for some value is an indication that
the associated quality is unimportant in this context and may be
discrimintaed against freely. A setting of 2 indicates that the quality
should be favored more than normal, and a setting of 3 means to go all
out to favor that quality. Only one quality should be raised above 1 at
any one time.
The above specification scheme is crude, but sufficiently expressive for
most needs in portable code. A compiler implementor will have specific
decisions to make -- whether to suppress inline expansions, whether to
type-check the arguments to CAR and CDR, whether to check for overflow
on arithmetic declared to be FIXNUM, whether to run the peephole
optimizer, etc. -- and it is up to him to decide how to tie these
decisions to the above values so as to match the users expressed wishes.
These decision criteria should be spelled out in that implementation's red
pages. For example, it might be the case that the peephole optimizer is
not run if COMPILER-SPEED > 1, that type checking for the argument to
CAR and CDR is suppressed if SPEED > SAFETY+1, etc.
----------------------------------------------------------------
23. Shall it be permitted for macros calls to expand into DECLARE forms
and then be recognized as valid declarations? For example:
(DEFMACRO CUBOIDS (&REST VARS)
`(DECLARE (TYPE (ARRAY SHORT-FLONUM 3) ,@VARS)
(SPECIAL ,@VARS)
(OPTIMIZE SPEED)
(INLINE HACK-CUBOIDS)))
(DEFUN CUBOID-EXPERT (A B C D)
(CUBOIDS A C)
...)
This would not allows macros calls *within* a DECLARE form, only allow
macros to expand into a DECLARE form.
(y) yes (n) no
24. Shall there be printer control variables ARRAY-PRINLEVEL and
ARRAY-PRINLENGTH to control printing of arrays? These would not
limit the printing of strings.
(y) yes (n) no
25. Shall lambda macros, as described below, be incorporated into
the language, and if so, shall they occupy the function name space
or a separate name space?
(f) function name space (s) separate name space (n) no lambda macros
----------------------------------------------------------------
Date: Wed, 22 Sep 1982 06:27:00 -0000
From: Howard I. Cannon <HIC at SCRC-TENEX at MIT-MC>
This is the documentation I wrote for lambda-macros as I implemented
them on the Lisp Machine. Please consider this a proposed definition.
Lambda macros may appear in functions where LAMBDA would have previously
appeared. When the compiler or interpreter detects a function whose CAR
is a lambda macro, they "expand" the macro in much the same way that
ordinary Lisp macros are expanded -- the lambda macro is called with the
function as its argument, and is expected to return another function as
its value. Lambda macros may be accessed with the (3:lambda-macro*
2name*) function specifier.
defspec lambda-macro function-spec lambda-list &body body
Analagously with 3macro*, defines a lambda macro to be called
2function-spec*. 2lambda-list* should consist of one variable, which
will be the function that caused the lambda macro to be called. The
lambda macro must return a function. For example:
lisp
(lambda-macro ilisp (x)
`(lambda (&optional ,@(second x) &rest ignore) . ,(cddr x)))
end_lisp
would define a lambda macro called 3ilisp* which would cause the
function to accept arguments like a standard Interlisp function -- all
arguments are optional, and extra arguments are ignored. A typical call
would be:
lisp
(fun-with-functional-arg #'(ilisp (x y z) (list x y z)))
end_lisp
Then, any calls to the functional argument that
3fun-with-functional-arg* executes will pass arguments as if the
number of arguments did not matter.
end_defspec
defspec deflambda-macro
3deflambda-macro* is like 3defmacro*, but defines a lambda macro
instead of a normal macro.
end_defspec
defspec deflambda-macro-displace
3deflambda-macro-displace* is like 3defmacro-displace*, but defines
a lambda macro instead of a normal macro.
end_defspec
defspec deffunction function-spec lambda-macro-name lambda-list &body body
3deffunction* defines a function with an arbitrary lambda macro
instead of 3lambda*. It takes arguments like 3defun*, expect that
the argument immediatly following the function specifier is the name of
the lambda macro to be used. 3deffunction* expands the lambda macro
immediatly, so the lambda macro must have been previously defined.
For example:
lisp
(deffunction some-interlisp-like-function ilisp (x y z)
(list x y z))
end_lisp
would define a function called 3some-interlisp-like-function*, that
would use the lambda macro called 3ilisp*. Thus, the function would
do no number of arguments checking.
end_defspec
----------------------------------------------------------------
26. Shall the floating-point manipulations described below be adopted?
(y) as described by MOON
(a) as amended (FLOAT-SIGN changed) by GLS
(n) do not adopt them
----------------------------------------------------------------
Date: Thu, 30 Sep 1982 09:55:00 -0000
From: MOON at SCRC-TENEX
I am not completely happy with the FLOAT-FRACTION, FLOAT-EXPONENT, and
SCALE-FLOAT functions in the Colander edition. At the meeting in August I
was assigned to make a proposal. I am slow.
A minor issue is that the range of FLOAT-FRACTION fails to include zero (of
course it has to), and is inclusive at both ends, which means that there
are two possible return values for some numbers. I guess that this ugliness
has to stay because some implementations require this freedom for hardware
reasons, and it doesn't make a big difference from a numerical analysis point
of view. My proposal is to include zero in the range and to add a note about
two possible values for numbers that are an exact power of the base.
A more major issue is that some applications that break down a flonum into
a fraction and an exponent, or assemble a flonum from a fraction and an
exponent, are best served by representing the fraction as a flonum, while
others are best served by representing it as an integer. An example of
the former is a numerical routine that scales its argument into a certain
range. An example of the latter is a printing routine that must do exact
integer arithmetic on the fraction.
In the agenda for the August meeting it was also proposed that there be
a function to return the precision of the representation of a given flonum
(presumably in bits); this would be in addition to the "epsilon" constants
described on page 143 of the Colander.
A goal of all this is to make it possible to write portable numeric functions,
such as the trigonometric functions and my debugged version of Steele's
totally accurate floating-point number printer. These would be portable
to all implementations but perhaps not as efficient as hand-crafted routines
that avoided bignum arithmetic, used special machine instructions, avoided
computing to more precision than the machine really has, etc.
Proposal:
SCALE-FLOAT x e -> y
y = (* x (expt 2.0 e)) and is a float of the same type as x.
SCALE-FLOAT is more efficient than exponentiating and multiplying, and
also cannot overflow or underflow unless the final result (y) cannot
be represented.
x is also allowed to be a rational, in which case y is of the default
type (same as the FLOAT function).
[x being allowed to be a rational can be removed if anyone objects. But
note that this function has to be generic across the different float types
in any case, so it might as well be generic across all number types.]
UNSCALE-FLOAT y -> x e
The first value, x, is a float of the same type as y. The second value, e,
is an integer such that (= y (* x (expt 2.0 e))).
The magnitude of x is zero or between 1/b and 1 inclusive, where b is the
radix of the representation: 2 on most machines, but examples of 8 and
16, and I think 4, exist. x has the same sign as y.
It is an error if y is a rational rather than a float, or if y is an
infinity. (Leave infinity out of the Common Lisp manual, though).
It is not an error if y is zero.
FLOAT-MANTISSA x -> f
FLOAT-EXPONENT x -> e
FLOAT-SIGN x -> s
FLOAT-PRECISION x -> p
f is a non-negative integer, e is an integer, s is 1 or 0.
(= x (* (SCALE-FLOAT (FLOAT f x) e) (IF (ZEROP S) 1 -1))) is true.
It is up to the implementation whether f is the smallest possible integer
(zeros on the right are removed and e is increased), or f is an integer with
as many bits as the precision of the representation of x, or perhaps a "few"
more. The only thing guaranteed about f is that it is non-negative and
the above equality is true.
f is non-negative to avoid problems with minus zero. s is 1 for minus zero
even though MINUSP is not true of minus zero (otherwise the FLOAT-SIGN function
would be redundant).
p is an integer, the number of bits of precision in x. This is a constant
for each flonum representation type (except perhaps for variable-precision
"bigfloats").
[I am amenable to converting these four functions into one function that
returns four values if anyone can come up with a name. EXPLODE-FLOAT is
the best so far, and it's not very good, especially since the traditional
EXPLODE function has been flushed from Common Lisp. Perhaps DECODE-FLOAT.]
[I am amenable to adding a function that takes f, e, and s as arguments
and returns x. It might be called ENCODE-FLOAT or MAKE-FLOAT. It ought to
take either a type argument or an optional fourth argument, the way FLOAT
takes an optional second argument, which is an example of the type to return.]
FTRUNC x -> fp ip
The FTRUNC function as it is already defined provides the fraction-part and
integer-part operations.
These functions exist now in the Lisp machines, with different names and slightly
different semantics in some cases. They are very easy to write.
Comments? Suggestions for names?
Date: Tue, 05 Oct 1982 03:55:00 -0000
From: Guy.Steele at CMU-10A
I support Moon's proposal, but would like to suggest that FLOAT-SIGN
be modified to
(FLOAT-SIGN x &optional (y (float 1 x)))
returns z such that x and z have same sign and (= (abs y) (abs z)).
In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
a useful function indeed in numerical code.
--Guy
----------------------------------------------------------------
27. Shall DEFMACRO, DEFSTRUCT, and other defining forms also be
allowed to take documentation strings as possible and appropriate?
(y) yes (n) no
28. Shall the following proposed revision of OPEN keywords be accepted?
(y) yes (n) no
----------------------------------------------------------------
Date: Mon, 04 Oct 1982 21:08:00 -0000
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
OPEN takes a filename as its first argument. The rest of its arguments
are keyword/value pairs.
WITH-OPEN-STREAM's first subform is a list of a variable (to be bound to
a stream), a filename, and the rest of the elements are keyword/value
pairs.
The keywords are as follows, with their possible values and defaults:
:DIRECTION :INPUT (the default), :OUTPUT, :APPEND, :OVERWRITE, :PROBE
:INPUT - The file is expected to exist. Output operations are not allowed.
:OUTPUT - The file is expected to not exist. A new file is created. Input
operations are not allowed.
:APPEND - The file is expected to exist. Input operations are not allowed.
New characters are appened to the end of the existing file.
:OVERWRITE - The file is expected to exist. All operations are allowed.
The "file pointer" starts at the beginning of the file.
:PROBE - The file may or may not exist. Neither input nor output operations
are allowed. Furthermore, it is not necessary to close the stream.
:CHARACTERS T (the default), NIL, :DEFAULT
T - Open the file for reading/writing of characters.
NIL - Open the file for reading/writing of bytes (non-negative integers).
:DEFAULT - Let the file system decide, based on the file it finds.
:BYTE-SIZE a fixnum or :DEFAULT (the default)
a fixnum - Use this byte size.
:DEFAULT - Let the file system decide, based on the file it finds.
:IF-EXISTS :ERROR (the default), :NEW-VERSION, :RENAME,
:RENAME-AND-DELETE, :OVERWRITE, :APPEND, :REPLACE
Ignored if direction is not :OUTPUT. This tells what to do if the file
that you're trying to create already exists.
:ERROR - Signal an error.
:NEW-VERSION - Create a file with the same filename except with "latest" version.
:RENAME - Rename the existing file to something else and proceed.
:RENAME-AND-DELETE - Rename the existing file and delete (but don't expunge,
if your system has undeletion) it, and proceed.
:OVERWRITE - Open for :OVERWRITE instead. (If your file system doesn't have
this, use :RENAME-AND-DELETE if you have undeletion and :RENAME otherwise.)
:APPEND - Open for :APPEND instead.
:REPLACE - Replace the existing file, deleting it when the stream is closed.
:IF-DOES-NOT-EXIST :ERROR (the default), :CREATE
Ignored if direction is neither :APPEND nor :OVERWRITE
:ERROR - Signal an error.
:CREATE - Create the file and proceed.
Notes:
I renamed :READ-ALTER to :OVERWRITE; :READ-WRITE might also be good.
The :DEFAULT values are very useful, although some systems cannot figure
out this information. :CHARACTERS :DEFAULT is especially useful for
LOAD. Having the byte size come from the file only when the option is
missing, as the latest Common Lisp manual says, is undesirable because
it makes things harder for programs that are passing the value of that
keyword argument as computed from an expression.
Example of OPEN:
(OPEN "f:>dlw>lispm.init" :DIRECTION :OUTPUT)
Example of WITH-OPEN-FILE:
(WITH-OPEN-FILE (STREAM "f:>dlw>lispm.init" :DIRECTION :OUTPUT) ...)
OPEN can be kept Maclisp compatible by recognizing whether the second
argument is a list or not. Lisp Machine Lisp does this for the benefit
of old programs. The new syntax cannot be mistaken for the old one.
I removed :ECHO because we got rid of MAKE-ECHO-STREAM at the last
meeting.
Other options that the Lisp Machine will probably have, and which might
be candidates for Common Lisp, are: :INHIBIT-LINKS, :DELETED,
:PRESERVE-DATES, and :ESTIMATED-SIZE.
----------------------------------------------------------------
-------