[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
TAILP-NIL (Version 5)
- To: cl-cleanup@sail.stanford.edu
- Subject: TAILP-NIL (Version 5)
- From: masinter.pa@Xerox.COM
- Date: 9 Dec 88 14:26 PST
I'd rather not have a debate about this one at X3J13. There will be little
enough time there. So lets get this one "straight" at least in our own
minds.
I occasionally forget about the caveat in CLtL that, unless otherwise
specified, a "list" is a proper list, and does not end in dotted tails. I
forgot about it when discussing this issue.
Given that caveat, doesn't it mean that currently it "is an error" to pass
a dotted list as the second argument to TAILP? And thus TAILP should use
ENDP?
!
Issue: TAILP-NIL
References: TAILP (p275)
Category: CLARIFICATION/CHANGE
Edit History: 13-Sep-88, version 1 by Walter van Roggen,
13-Sep-88, version 2 by Pitman
18-Oct-88, version 3 by van Roggen (just one proposal)
01-Dec-88, version 4 by Pitman (minor edits per discussion)
9-Dec-88, Version 5 by Masinter (clarify EQL)
Problem Description:
CLtL (p275) specifies TAILP as:
TAILP sublist list [Function]
This predicate is true if SUBLIST is a sublist of LIST (i.e.,
one of the conses that makes up LIST); otherwise, it is false.
Another way to look at this is that TAILP is true if
(NTHCDR n list) is SUBLIST, for some value of N. See LDIFF.
Two implementations of this definition might be:
(defun tailp (sublist list) ;Definition "A"
(do ((list list (cdr list)))
((endp list) nil)
(if (eql sublist list)
(return t))))
(defun tailp (sublist list) ;Definition "B"
(do ((list list (cdr list)))
((atom list) (eql list sublist))
(if (eql sublist list)
(return t))))
They differ only in their treatment of the atomic case.
At issue is the fact that () is a list, and hence some would
argue that it is a sublist of all other lists. On the other hand,
the definition of TAILP seems to imply that being a cons is a
necessary precondition of being a "sublist".
Also at issue is the question of whether dotted lists are permissible
second arguments.
Proposal (TAILP-NIL:T):
Strike any text in the definition of TAILP which suggests that a
sublist must be a cons.
Clarify that (TAILP sublist list) returns true iff (NTHCDR n list) is
sublist for some value of n, and false otherwise.
Note, however, that since the list may be dotted, so the end test
used by TAILP must be ATOM, not ENDP. That is, if (TAILP x l)
returns true, it means there was n such that (NTHCDR n list) would
return x; however, it doesn't follow that if TAILP returns false,
it is safe to go blithely NTHCDR's into the list looking for it,
since the list might be dotted and NTHCDR might hit bad data.
Note that TAILP uses EQL or equivalent to compare
sublist to list in the case where sublist is a number, etc.
Rationale:
This is more consistent with the definition of LDIFF, which
gives a useful meaning to arbitrary atomic SUBLIST arguments.
This gives a more elegant definition of SUBLIST, allowing it to
refer to any list -- including the empty list -- which is a
part of another list.
Some reasons for preferring an ATOM check to ENDP include:
- The name TAILP suggests tails, not sublists. Some users might
expect this distinction to mean that data more general than
proper sublists.
- Making TAILP require lists limits its usefulness. If we did
not make this choice, some users would end up having to write
their own extended TAILP which we could just as well have
provided compatibly.
- TAILP is not considered to be used frequently enough in code
that the minor loss in speed to an ATOM check is worth the
lost functionality. Indeed, expanding the scope of its
capabilities may lead to more uses for TAILP.
- Other operators (eg, APPEND) have recently been extended to
treat dotted lists in an interesting way because users have
expressed a desire for this. As such, this change is
culturally consistent.
- Some implementations already support this feature, and the
wording in CLtL is sufficiently ambiguous that some users
might think it appropriate to depend on the feature. In the
absence of compelling efficiency reasons to the contrary,
we should lean toward extending some implementations rather
than tightening others in our efforts to achieve cross-dialect
consistency.
Examples:
#1: (LET ((X '(B C))) (TAILP X (CONS 'A X)))
should return T in all implementations.
#2: (TAILP '(X Y) '(A B C))
should return NIL in all implementations.
#3: (TAILP '() '(A B C))
returns T under this proposal.
#4: (TAILP 3 '(A B C))
returns NIL under this proposal.
#5: (TAILP 3 '(A B C . 3))
returns T under this proposal.
#6: (TAILP '(X Y) '(A B C . 3))
returns NIL under this proposal.
Current Practice:
Symbolics Genera is consistent with TAILP-NIL:T.
Neither Lucid nor VAX LISP currently implements TAILP-NIL:T.
VAX LISP effectively implements definition "A" from the
Problem Description above.
Cost to Implementors:
An implementation of TAILP-NIL:T is given as Definition "B" in the
problem description.
Some implementations might have compiler optimizers for these definitions
as well, so a slight amount of additional effort might be required.
Cost to Users:
Given that current practice varies widely on the disputed case,
this is unlikely to have a practical effect on existing portable code.
Benefits:
Avoids unnecessary incompatibilities between implementations.
Non-Benefits:
Slows down TAILP slightly in some implementations because ENDP is
potentially faster than ATOM.
Discussion:
This issue was first raised in ">GLS>clarifications.text" of 12/06/85.
It recommended an earlier proposal, TAILP-NIL:NIL, which is effectively
equivalent to Definition "A" from the Problem Description.
Pitman introduced TAILP-NIL:T as an alternative, arguing that the
definition TAILP-NIL:NIL offered no practical value to programmers
in the disputed situations, while TAILP-NIL:T was of arguable usefulness.
Pitman and van Roggen support TAILP-NIL:T.
It was suggested more than once by more than one cleanup
committee member that we remove TAILP from the language
"since almost nobody uses it".