Small fixes & updates.

This commit is contained in:
shivers 1999-10-02 14:17:50 +00:00
parent 76dd7b8b07
commit aaf66a22d8
4 changed files with 115 additions and 88 deletions

View File

@ -79,18 +79,34 @@
;;; This is carefully tuned code; do not modify casually.
;;; - It is careful to share storage when possible;
;;; - Side-effecting code tries not to perform redundant writes.
;;;
;;; That said, a port of this library to a specific Scheme system might wish
;;; to tune this code to exploit particulars of the implementation. In
;;; particular, the n-ary mapping functions are particularly slow and
;;; cons-intensive, and are good candidates for tuning. I have coded fast
;;; paths for the single-list cases, but what you really want to do is exploit
;;; the fact that the compiler usually knows how many arguments are being
;;; passed to a particular application of these functions -- they are usually
;;; explicitly called, not passed around as higher-order values. If you can
;;; arrange to have your compiler produce custom code or custom linkages based
;;; on the number of arguments in the call, you can speed these functions up
;;; a *lot*. But this kind of compiler technology no longer exists in the
;;; Scheme world as far as I can see.
;;; to tune this code to exploit particulars of the implementation.
;;; The single most important compiler-specific optimisation you could make
;;; to this library would be to add rewrite rules or transforms to:
;;; - transform applications of n-ary procedures (e.g. LIST=, CONS*, APPEND,
;;; LSET-UNION) into multiple applications of a primitive two-argument
;;; variant.
;;; - transform applications of the mapping functions (MAP, FOR-EACH, FOLD,
;;; ANY, EVERY) into open-coded loops. The killer here is that these
;;; functions are n-ary. Handling the general case is quite inefficient,
;;; requiring many intermediate data structures to be allocated and
;;; discarded.
;;; - transform applications of procedures that take optional arguments
;;; into calls to variants that do not take optional arguments. This
;;; eliminates unnecessary consing and parsing of the rest parameter.
;;;
;;; These transforms would provide BIG speedups. In particular, the n-ary
;;; mapping functions are particularly slow and cons-intensive, and are good
;;; candidates for tuning. I have coded fast paths for the single-list cases,
;;; but what you really want to do is exploit the fact that the compiler
;;; usually knows how many arguments are being passed to a particular
;;; application of these functions -- they are usually explicitly called, not
;;; passed around as higher-order values. If you can arrange to have your
;;; compiler produce custom code or custom linkages based on the number of
;;; arguments in the call, you can speed these functions up a *lot*. But this
;;; kind of compiler technology no longer exists in the Scheme world as far as
;;; I can see.
;;;
;;; Note that this code is, of course, dependent upon standard bindings for
;;; the R5RS procedures -- i.e., it assumes that the variable CAR is bound
@ -1192,23 +1208,25 @@
;;; linear-time algorithm to kill the dups. Or use an algorithm based on
;;; element-marking. The former gives you O(n lg n), the latter is linear.
(define (delete-duplicates elt= lis)
(check-arg procedure? elt= delete-duplicates)
(let recur ((lis lis))
(if (null-list? lis) lis
(let* ((x (car lis))
(tail (cdr lis))
(new-tail (recur (delete x tail elt=))))
(if (eq? tail new-tail) lis (cons x new-tail))))))
(define (delete-duplicates lis . maybe-=)
(let ((elt= (:optional maybe-= equal?)))
(check-arg procedure? elt= delete-duplicates)
(let recur ((lis lis))
(if (null-list? lis) lis
(let* ((x (car lis))
(tail (cdr lis))
(new-tail (recur (delete x tail elt=))))
(if (eq? tail new-tail) lis (cons x new-tail)))))))
(define (delete-duplicates! elt= lis)
(check-arg procedure? elt= delete-duplicates!)
(let recur ((lis lis))
(if (null-list? lis) lis
(let* ((x (car lis))
(tail (cdr lis))
(new-tail (recur (delete! x tail elt=))))
(if (eq? tail new-tail) lis (cons x new-tail))))))
(define (delete-duplicates! lis maybe-=)
(let ((elt= (:optional maybe-= equal?)))
(check-arg procedure? elt= delete-duplicates!)
(let recur ((lis lis))
(if (null-list? lis) lis
(let* ((x (car lis))
(tail (cdr lis))
(new-tail (recur (delete! x tail elt=))))
(if (eq? tail new-tail) lis (cons x new-tail)))))))
;;; alist stuff
@ -1382,7 +1400,7 @@
((null? ans) lis) ; if we don't have to.
((eq? lis ans) ans)
(else
(fold (lambda (elt ans) (if (any (lambda (x) (= x elt)))
(fold (lambda (elt ans) (if (any (lambda (x) (= x elt)) ans)
ans
(cons elt ans)))
ans lis))))

View File

@ -60,7 +60,7 @@
;; list-copy lis
(list-copy (proc (:value) :value))
(circular-list (proc (:value &opt :value) :pair))
(circular-list (proc (:value &rest :value) :pair))
; ((:iota iota:)
; (proc (:number &opt :number :number) :value))
@ -102,7 +102,7 @@
(unzip4 (proc (:value) (some-values :value :value :value :value)))
(unzip5 (proc (:value) (some-values :value :value :value :value :value)))
(count (proc ((proc (:value) :boolean) :value) :exact-integer))
(count (proc ((proc (:value &rest :value) :boolean) :value) :exact-integer))
((fold fold-right)
(proc ((proc (:value :value &rest :value) :value)

View File

@ -1,8 +1,7 @@
<!doctype html public '-//W3C//DTD HTML 4.0//EN'
'http://www.w3.org/TR/REC-html40/strict.dtd'>
<!-- insert p tags
Is there a portable way to write an em-dash?
<!-- Is there a portable way to write an em-dash?
Can I have bangs, plusses, or slashes in #tags? Spaces?
Yes: plus, bang, star No: space Yes: slash, question, ampersand
You can't put sharp in a path, so anything goes, really.
@ -86,7 +85,7 @@
/* R5RS proc names are in italic; extended R5RS names
** in italic boldface.
*/
span.r5rs-proc { font-style: italic; }
span.r5rs-proc { font-weight: bold; }
span.r5rs-procx { font-style: italic; font-weight: bold; }
/* Spread out bibliographic lists. */
@ -111,9 +110,13 @@
** here. Perhaps, one day, when these rendering bugs are fixed,
** this gross hackery can be removed.
*/
dt.proc-def1 { margin-top: 2ex; margin-bottom: 0ex; }
dt.proc-def1 { margin-top: 3ex; margin-bottom: 0ex; }
dt.proc-defi { margin-top: 0ex; margin-bottom: 0ex; }
dt.proc-defn { margin-top: 0ex; margin-bottom: 0.5ex; }
dt.proc-def { margin-top: 3ex; margin-bottom: 0.5ex; }
pre { margin-top: 1ex; }
dd.proc-def { margin-bottom: 2ex; margin-top: 0.5ex; }
/* For the index of procedures.
@ -123,7 +126,7 @@
pre.proc-index { margin-top: 0ex; }
/* Spread out bibliographic lists. */
dt.biblio { margin-bottom: 0ex; }
dt.biblio { margin-top: 3ex; margin-bottom: 0ex; }
dd.biblio { margin-bottom: 1ex; }
</style>
</head>
@ -218,7 +221,7 @@ of the other big, full-featured Schemes. The complete list of list-processing
systems I checked is:
<div class=indent>
<abbr title="Revised^4 Report on Scheme">R4RS</abbr>/<abbr title="Revised^5 Report on Scheme"><a href="#R5RS">R5RS</a></abbr> Scheme, MIT Scheme, Gambit, RScheme, MzScheme, slib,
<a href="#CLtL2">Common Lisp</a>, Bigloo, guile, T, APL and the SML standard basis
<a href="#CommonLisp">Common Lisp</a>, Bigloo, guile, T, APL and the SML standard basis
</div>
<p>
As a result, the library I am proposing is fairly rich.
@ -250,8 +253,7 @@ implementation. I have placed this source on the Net with an unencumbered,
</ul>
<li>It is written for clarity and well-commented. The current source is
1436 lines of text, of which 690 are source code; the rest being comments
and blank lines.
706 lines of source code and 818 lines of comments and white space.
<li>It is written for efficiency. Fast paths are provided for common
cases. Side-effecting procedures such as <code>filter!</code> avoid unnecessary,
@ -277,7 +279,7 @@ library and get good results with it.
<p>
Here is a short list of the procedures provided by the list-lib package.
<a href="#R5RS">R5RS</a></abbr> procedures are shown in
<span class=r5rs-proc>italic</span class=r5rs-proc>;
<span class=r5rs-proc>bold</span class=r5rs-proc>;
extended <a href="#R5RS">R5RS</a></abbr>
procedures, in <span class=r5rs-procx>bold italic</span>.
<div class=indent>
@ -658,7 +660,7 @@ The following items are not in this library:
<li>Tree-processing routines
</ul>
<p>
They shound have their own <abbr title="Scheme Request for Implementation">SRFI</abbr> specs.
They should have their own <abbr title="Scheme Request for Implementation">SRFI</abbr> specs.
<p>
@ -688,16 +690,15 @@ The templates given below obey the following conventions for procedure formals:
<td> A natural number (an integer &gt;= 0)
<tr valign=baseline><th align=left> <var>proc</var>
<td> A procedure
<tr valign=baseline><th align=left> <var>pred</var>
<td> A procedure whose return value is treated as a boolean
<tr valign=baseline><th align=left> <var>=</var>
<td> A boolean procedure taking two arguments
<tr valign=baseline><th align=left> <var>pred</var>
<td> A boolean procedure taking one argument
</table>
<p>
It is an error to pass a circular or dotted list to a procedure not
defined to accept such an argument. Such a procedure may either signal
an error or diverge when passed a circular list.
defined to accept such an argument.
<!--========================================================================-->
<h2><a name="Constructors">Constructors</a></h2>
@ -771,7 +772,7 @@ an error or diverge when passed a circular list.
<div class=indent><code>
(cons <var>elt<sub>1</sub></var> (cons <var>elt<sub>2</sub></var> (cons ... <var>elt<sub>n</sub></var>)))
</code></div>
This function is called <code>list*</code> in <a href="#CLtL2">Common Lisp</a> and about
This function is called <code>list*</code> in <a href="#CommonLisp">Common Lisp</a> and about
half of the Schemes that provide it,
and <code>cons*</code> in the other half.
<pre class=code-example>
@ -783,7 +784,7 @@ an error or diverge when passed a circular list.
==== make-list
============================================================================-->
<a name="make-list"></a>
<dt class=proc-def> <code class=proc-def>make-list <var>n [fill] -&gt; list</var></code>
<dt class=proc-def> <code class=proc-def>make-list</code> <var>n [fill] -&gt; list</var>
<dd class=proc-def>
Returns an <var>n</var>-element list,
whose elements are all the value <var>fill</var>.
@ -870,7 +871,7 @@ partition the entire universe of Scheme values.
Note that this definition rules out circular lists. This
function is required to detect this case and return false.
<p>
Nil-terminated lists are called "proper" lists by <abbr title="Revised^5 Report on Scheme"><a href="#R5RS">R5RS</a></abbr> and <a href="#CLtL2">Common Lisp</a>.
Nil-terminated lists are called "proper" lists by <abbr title="Revised^5 Report on Scheme"><a href="#R5RS">R5RS</a></abbr> and <a href="#CommonLisp">Common Lisp</a>.
The opposite of proper is improper.
<p>
<abbr title="Revised^5 Report on Scheme"><a href="#R5RS">R5RS</a></abbr> binds this function to the variable <code>list?</code>.
@ -1011,7 +1012,8 @@ partition the entire universe of Scheme values.
<code>(eq? <var>x</var> <var>y</var>)</code> => <code>(<var>elt=</var> <var>x</var> <var>y</var>)</code>.
</div>
Note that this implies that two lists which are <code>eq?</code>
are always <var>list=</var>, as well.
are always <var>list=</var>, as well; implementations may exploit this
fact to "short-cut" the element-by-element comparisons.
<pre class=code-example>
(list= eq?) => #t ; Trivial cases
(list= eq? '(a)) => #t
@ -1318,6 +1320,8 @@ partition the entire universe of Scheme values.
<pre class=code-example>
(append '(a b) '(c . d)) => (a b c . d)
(append '() 'a) => a
(append '(x y)) => (x y)
(append) => ()
</pre>
<code>append!</code> is the "linear-update" variant of <code>append</code>
@ -1565,7 +1569,8 @@ partition the entire universe of Scheme values.
(pair-fold <var>kons</var> (<var>kons</var> <var>lis</var> <var>knil</var>) tail))
(pair-fold <var>kons</var> <var>knil</var> <code>'()</code>) = <var>knil</var>
</pre>
The <var>kons</var> function may reliably apply <code>set-cdr!</code> to the pairs it is given
For finite lists, the <var>kons</var> function may reliably apply
<code>set-cdr!</code> to the pairs it is given
without altering the sequence of execution.
<p>
Example:
@ -1754,10 +1759,10 @@ Otherwise, return <code>(fold <var>f</var> (car <var>list</var>) (cdr <var>li
<pre class=code-example>
;; List of squares: 1^2 ... 10^2
(unfold (lambda (x) (&gt; x 10))
(lambda (x) (* x x))
(lambda (x) (+ x 1))
1)
(unfold-right (lambda (x) (&gt; x 10))
(lambda (x) (* x x))
(lambda (x) (+ x 1))
1)
(unfold-right null-list? car cdr lis) ; Copy a proper list.
@ -1870,10 +1875,7 @@ Otherwise, return <code>(fold <var>f</var> (car <var>list</var>) (cdr <var>li
specification to allow the arguments to be of unequal length;
it terminates when the shortest list runs out.
<p>
At least one of the argument lists must be finite:
<pre class=code-example>
(map + '(3 1 4 1) (circular-list 1 0)) => (4 1 5 1)
</pre>
At least one of the argument lists must be finite.
<!--
==== append-map!
@ -2110,7 +2112,7 @@ these procedures work when applied to different kinds of lists:
satisfying the search criteria.
</dl>
<p>
Here are some examples, using the <code>find</code> and <code>any</code> procedures as a canonical
Here are some examples, using the <code>find</code> and <code>any</code> procedures as canonical
representatives:
<pre class=code-example>
;; Proper list -- success
@ -2950,8 +2952,8 @@ assistance.
<p>
I am also grateful the authors, implementors and documentors of all the systems
mentioned in the introduction. Aubrey Jaffer and Kent Pitman should be noted
for their work in producing Web-accessible versions of the R5RS and Common
Lisp spec, which was a tremendous aid.
for their work in producing Web-accessible versions of the R5RS and
<a href="#CommonLisp">Common Lisp</a> spec, which was a tremendous aid.
<p>
This is not to imply that these individuals necessarily endorse the final
results, of course.
@ -2998,11 +3000,17 @@ results, of course.
<p>
<dl>
<dt class=biblio><strong><a name="CLtL2">[CLtL2]</a></strong></dt>
<dt class=biblio><strong><a name="CommonLisp">[CommonLisp]</a></strong></dt>
<dd><em>Common Lisp: the Language</em><br>
Guy L. Steele Jr. (editor).<br>
Digital Press, Maynard, Mass., second edition 1990.<br>
Available at <a href="http://www.harlequin.com/education/books/HyperSpec/">
Available at <a href="http://www.elwood.com/alu/table/references.htm#cltl2">
http://www.elwood.com/alu/table/references.htm#cltl2</a>.
<p>
The Common Lisp "HyperSpec," produced by Kent Pitman, is essentially
the ANSI spec for Common Lisp:
<a href="http://www.harlequin.com/education/books/HyperSpec/">
http://www.harlequin.com/education/books/HyperSpec/</a>.
<dt class=biblio><strong><a name="R5RS">[R5RS]</a></strong></dt>

View File

@ -1,13 +1,9 @@
The SRFI-1 list library -*- outline -*-
Olin Shivers
98/10/16
Last Update: 99/9/11
Last Update: 99/10/2
Todo: carefully proofread.
Netscape prints with insufficient space between proc specs --
see list=, for example. Mess about with css some more.
Emacs should display this document is in outline mode. Say c-h m for
Emacs should display this document in outline mode. Say c-h m for
instructions on how to move through it by sections (e.g., c-c c-n, c-c c-p).
During the SRFI discussion period, the current draft may be found at
ftp://ftp.ai.mit.edu/people/shivers/srfi/srfi-1/srfi-1.txt
@ -97,8 +93,7 @@ implementation. I have placed this source on the Net with an unencumbered,
- Use of a simple CHECK-ARG procedure for argument checking.
- It is written for clarity and well-commented. The current source is
1436 lines of text, of which 690 are source code; the rest being comments
and blank lines.
706 lines of source code and 818 lines of comments and white space.
- It is written for efficiency. Fast paths are provided for common
cases. Side-effecting procedures such as FILTER! avoid unnecessary,
@ -424,7 +419,7 @@ The following items are not in this library:
- Sort routines
- Destructuring/pattern-matching macro
- Tree-processing routines
They shound have their own SRFI specs.
They should have their own SRFI specs.
@ -442,12 +437,11 @@ The templates given below obey the following conventions for procedure formals:
object, value Any value
n, i A natural number (an integer >= 0)
proc A procedure
pred A procedure whose return value is treated as a boolean
= A boolean procedure taking two arguments
pred A boolean procedure taking one argument
It is an error to pass a circular or dotted list to a procedure not
defined to accept such an argument. Such a procedure may either signal
an error or diverge when passed a circular list.
defined to accept such an argument.
** Constructors
===============
@ -614,7 +608,8 @@ list= elt= list1 ... -> boolean
it must be the case that
(eq? x y) => (elt= x y).
Note that this implies that two lists which are EQ? are always LIST=,
as well.
as well; implementations may exploit this fact to "short-cut" the
element-by-element comparisons.
(list= eq?) => #t ; Trivial cases
(list= eq? '(a)) => #t
@ -776,6 +771,8 @@ append! list1 ... -> value
(append '(a b) '(c . d)) ==> (a b c . d)
(append '() 'a) ==> a
(append '(x y)) ==> (x y)
(append) ==> ()
APPEND! is the "linear-update" variant of APPEND -- it is allowed, but
not required, to alter cons cells in the argument lists to construct
@ -932,8 +929,8 @@ pair-fold kons knil clist1 clist2 ... -> value
(pair-fold kons knil '()) = knil
The KONS function may reliably apply SET-CDR! to the pairs it is given
without altering the sequence of execution.
For finite lists, the KONS function may reliably apply SET-CDR! to the
pairs it is given without altering the sequence of execution.
Example:
;;; Destructively reverse a list.
@ -1130,8 +1127,7 @@ for-each proc clist1 clist2 ... -> unspecified R5RS+
to allow the arguments to be of unequal length; it terminates
when the shortest list runs out.
At least one of the argument lists must be finite:
(map + '(3 1 4 1) (circular-list 1 0)) => (4 1 5 1)
At least one of the argument lists must be finite.
append-map f clist1 clist2 ... -> value
append-map! f clist1 clist2 ... -> value
@ -1279,7 +1275,7 @@ these procedures work when applied to different kinds of lists:
successful* -- that is, if the list contains an element
satisfying the search criteria.
Here are some examples, using the FIND and ANY procedures as a canonical
Here are some examples, using the FIND and ANY procedures as canonical
representatives:
;; Proper list -- success
(find even? '(1 2 3)) => 2
@ -1324,7 +1320,7 @@ find pred clist -> value
FIND -- FIND-TAIL has no such ambiguity:
(cond ((find-tail pred lis) => (lambda (pair) ...)) ; Handle (CAR PAIR)
(else ...)) ; Search failed.
find-tail pred clist -> pair or false
Return the first pair of CLIST whose car satisfies PRED. If no pair does,
return false.
@ -1843,11 +1839,15 @@ SRFI web site:
http://srfi.schemers.org/
[CLtL2]
[CommonLisp]
Common Lisp: the Language
Guy L. Steele Jr. (editor).
Digital Press, Maynard, Mass., second edition 1990.
Available at http://www.harlequin.com/education/books/HyperSpec/
Available at http://www.elwood.com/alu/table/references.htm#cltl2
The Common Lisp "HyperSpec," produced by Kent Pitman, is essentially
the ANSI spec for Common Lisp:
http://www.harlequin.com/education/books/HyperSpec/
[R5RS]
Revised^5 Report on the Algorithmic Language Scheme,
@ -1905,8 +1905,9 @@ Ispell dumps "buffer local" words here. Please ignore.
LocalWords: arg LISTi pred cond LISTn ANY's EVERY's Uniquifying lg ridentity
LocalWords: eq netnews generalise Maciej Stachowiak al Bewig LocalWords ELTi
LocalWords: anamorphism apomorphism CLISTi ALIST's url ceteris eltn caar KNULL
LocalWords: deconstructor RIGHT's KAR KDR kar kdr knull HTML CLtL Clinger
LocalWords: Rees Bawden Blandy Bornstein Bothner Carrico Currie Dybvig
LocalWords: Egorov Feeley Matthias Felleisen Flatt Hilsdale Hukriede
LocalWords: Kolbly Shriram Krishnamurthi Jussi Piitulainen Pokorny Joerg
LocalWords: Sperber Wittenberger documentors Jaffer
LocalWords: deconstructor RIGHT's KAR KDR kar kdr knull HTML CLtL Clinger gen
LocalWords: Rees Bawden Blandy Bornstein Bothner Carrico Currie Dybvig expt
LocalWords: Egorov Feeley Matthias Felleisen Flatt Hilsdale Hukriede CLISTs
LocalWords: Kolbly Shriram Krishnamurthi Jussi Piitulainen Pokorny Joerg Todo
LocalWords: Sperber Wittenberger documentors Jaffer initialised consed IE
LocalWords: disarranging SIGPLAN CommonLisp cltl HyperSpec