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

Restricting the procedures to proper lists



The response from the discussion list has been overwhelmingly against defining
these procedures to produce results when given dotted lists, in favor of
increased error checking. Accordingly, I have made a careful pass through the
Common Lisp spec, and brought the list-lib procedures into line with the
proper-list constraints chosen by Common Lisp. You can check the Common Lisp
spec on-line at Kent Pitman's excellent "hyperspec"
    http://www.harlequin.com/education/books/HyperSpec/
if you wish to see exactly what Common Lisp does. In particular, see
the note/clarification on the handling of dotted lists at
    http://www.harlequin.com/education/books/HyperSpec/Issues/iss138-writeup.html
I am personally against this, but am bowing to the general consensus.

For me, the current BIG QUESTION is this: some list-processing procedures
do not always examine the whole list -- such as the procedures that search
lists, like FIND, MEMBER, etc. Suppose we decide to restrict these
procedures to proper lists. What is the spec going to be for invocations
where the procedure never examines the whole list, and so cannot see the
terminator? For example,
    (find even? '(1 2 3 . d))
is going to return 2, even if it is supposed to be defined only over proper
lists.  That is, it's unlikely that any implementation would ever enforce the
proper-list typing of its list parameter. So how should the spec read?  Should
we say that in this case, is it an error that the procedure is not required to
detect, allowing the procedure to produce an undefined result and effect? So
you should never *rely* on FIND working on an improper list?  I would
appreciate some discussion on this. 

I'm introducing a new function, NULL-LIST?, which is exactly Common Lisp's
ENDP. It returns true on (), false on a pair, and raises an error on other
arguments. This toughens up the Common Lisp spec, which allows ENDP to be
implemented as (NOT (PAIRP x)) for speed. If you want to lobby for allow
the sleaze factor in the spec, say so now.

These procedures take proper lists for their parameters.
They will signal an error when passed a dotted list.
They may diverge or signal an error when passed a circular list.
    filter  partition  remove
    filter! partition! remove! 
    del  delq  delv  delete 
    del! delq! delv! delete!
    alist-copy
    delq-duplicates  delv-duplicates  delete-duplicates  del-duplicates 
    delq-duplicates! delv-duplicates! delete-duplicates! del-duplicates!
    alist-delete  del-ass  del-assq  del-assv  del-assoc
    alist-delete! del-ass! del-assq! del-assv! del-assoc!
    for-each pair-for-each
    reduce reduce-right
    unzip1 unzip2 unzip3 unzip4 unzip5 
    reverse reverse! 
    union, intersection, etc.

These procedures take proper lists for their parameters.
They will raise an error *if* they encounter a non-nil dotted-list 
terminator. Question: what do we say about these procedures when they
are passed a dotted list that they do not detect (i.e., when they
terminate without going to the end of the list, such as 
    (find even? '(1 2 3 4 . d))
Is it an error that the procedure is not required to detect, allowing
the procedure to produce an undefined result and effect? Is it OK?
They may diverge or signal an error when passed a circular list.
    mem member memq memv
    ass assoc assq assv 
    find find-tail any every list-index

These procedures take proper or circular lists for their parameters.
They will signal an error if given a dotted list.
    length length+

These procedures accept proper or circular lists.
At least one list must be proper (finite).
The issue of "what is the spec for long dotted-lists when the
procedure terminates early on a shorter proper list" remains.
    append-map append-map! 
    map filter-map map-in-order map!
    fold fold-right pair-fold pair-fold-right
    zip

Issue of nil-termination does not apply to result or is trivial:
    xcons tree-copy make-list list-tabulate list cons* alist-cons
    circular-list iota
    unfold unfold/tail
	These are all constructors
    first second third fourth fifth sixth seventh eighth ninth tenth
	Exactly CAR, CADR, ...
    append-reverse append-reverse!
	(These follow the constraints of (APPEND (REVERSE x) y)
	 and (APPEND (REVERSE! x) y).)
    cons pair? null? not-pair? null-list? list?
    circular-list? proper-list? dotted-list?
    car cdr ... cdddar cddddr set-car! set-cdr! 

All but last arg must be proper list; the final argument may any value at all.
    append append!

Accepts proper or dotted list:
    list-copy [e.g., (list-copy '(a b . c)) => (a b . c)]
    take-right drop-right drop-right!
	By analogy to Common Lisp's LAST, BUTLAST & NBUTLAST.
    last last-pair

Accepts proper, dotted, or circular list:
    drop
    list-ref 
	By analogy to Common Lisp's NTHCDR and NTH.
    take take!
	As DROP goes, so should these.