[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
GLS's clarifications list (moderately long)
Apologies if any of the following have been discussed and resolved before.
+ COMMON LISP's #n=/#n# syntax invites the creation of circular lists. For
example, the following seems more tasteful than the example with star, and
is, I believe, fairly perspicuous:
(mapcar #'cons p-list '#0=(property value . #0#))
Another place where circular lists are useful is with progv. Suppose I'm
passed a list of dynamic variables to be bound and initialized to nil, but
whose length I don't know. Three obvious ways are (1) to cons up a list
of nils at runtime, (2) write a recursive macro, and (3), the following, which
seems clearest:
(progv var-list '#0=(nil . #0#)
...)
Whether circular arguments to such functions are allowed or forbidden, all
the functions where folks might be tempted to use them may need to be identified,
so an explicit "it is an error to pass a circular list ...," "implementations
are required to support circular lists ...," or whatever can be put in their
descriptions. Alternatively some general rule, or possibly a table, can be
constructed. Since people can do some pretty tasteless things, the list
of possibilities is quite large. So far I've come up with the following,
although I'm sure I've missed some:
- map, every, some, notany, and notevery
- mapc, mapcan, mapcar, mapcon, mapl, and maplist
- the format directives ~?, ~{, ~:{, and ~:@{
- progv
- dolist
- the following, so long as :end (or possibly :end1, :end2, or :count) is
supplied, although for most of them I have a lot of trouble imagining why
anyone would actually try to use a circular list:
count, count-if, count-if-not, delete, delete-if, delete-if-not,
fill, find, find-if, find-if-not, mismatch, nsubstitute, nsubstitute-if,
nsubstitute-if-not, position, position-if, position-if-not, reduce,
remove, remove-if, remove-if-not, remove-duplicates, replace, search,
substitute, substitute-if, and substitute-if-not
- getting even more far-fetched, if tests with side-effects are allowed
(possibly in conjuction with :test or :test-if-not) a lot of the functions
in the previous item together with the following are possibilities:
assoc, assoc-if-not, member, member-if, member-if-not, adjoin, union,
nunion, intersection, nintersection, set-difference, nset-difference,
set-exclusive-or, nset-exclusive-or, subset, rassoc, rassoc-if,
rassoc-if-not, and pushnew.
- does GLS's clarification of (tailp '() L) imply that the following is legal?
(tailp '() '#0=(x . #0#))
I can imagine someone tastefully using everything down to and including dolist
with circular lists, even though I'd never use most of them myself. Below that
everything seems a revolting quagmire, and should explicitly "be an error."
Does COMMON LISP guarantee that we can successfully call inspect on a circular
list or structure? It should.
A related clarification. Not only can data be circular, so can code.
It should probably "be an error" to try to eval something like
(progn . #0=((f) . #0#)) ; an ugly way of saying (loop (f))
+ From: SCRC-STONY-BROOK.arpa!KMP@uw-beaver.UUCP (Kent M Pitman)
Certainly I've had a lot more use for NAND and NOR than for XOR.
Xor might be useful in that it avoids having to either repeat an expression or
introduce a let variable. This is what distinguishes it from nand and nor.
For example,
(nand
(one-of-my-special-expressions-p x)
(apply (get (first x) 'dispatcher) (rest x)) )
can be written
(not (and
(one-of-my-special-expressions-p x)
(apply (get (first x) 'dispatcher) (rest x)) ))
which isn't much hairier, while
(xor
(one-of-my-special-expressions-p x)
(apply (get (first x) 'dispatcher) (rest x)) )
can be written
(if (one-of-my-special-expressions-p x)
(not (apply (get (first x) 'dispatcher) (rest x)))
(apply (get (first x) 'dispatcher) (rest x)) )
or
(let* ((x (one-of-my-special-expressions-p x))
(y (apply (get (first x) 'dispatcher) (rest x))) )
(if x (not y) y) )
both of which are, I believe, hairier.
Such reasoning led me write an xor several times. But neither I nor anyone
else ever used the ones I wrote, as far as I can tell. Ever. It probably has
no place in the language, especially since the rare someone who actually needs
it a lot can easily enough write one.
+ Regarding adding the functions hash-table-rehash-size, hash-table-rehash-threshold,
hash-table-size, and hash-table-test:
- Would these be setf'able? I would expect the first two could be done easily,
and even the size and test can be changed by rehashing the table.
- What does hash-table-test return? 'eql or #'eql?
While on the subject of hash tables, here are a couple more points that have been
bothering me:
- Why is there no way to hash on arrays (other than bit-vectors and strings) and
structures? Should #'equalp hash tables also be supported? Things I would
have preferred to implement as structures I've implemented as lists,
defining accessors by hand, just so I can hash on them.
- Shouldn't it be made explicit that hash tables may store the actual key,
and that destructive operations should not be performed on it? Or is this
even true? I suppose one might expect a #'eq hash table to continue working
even if you mucked around with the keys stored in it, even though one would
probably not expect that of a #'equal hash table (yuk).
+ Regarding requiring that implementations support tracing of macros: What does
it mean to trace a macro? Do you just print information when the macro is
expanded, or do you arrange to have information printed every time the expansion
is eval'd? There are LISPs out there doing it each way.
+ Regarding globals: Standard LISP has the notion of a global. Nearly every
time I've modified a Standard LISP program that used globals extensively I've
had to change one or two of them to fluids (i.e. special) because something the
original implementor (often myself) thought no one would ever want to rebind I
neede to rebind. Even worse are the plethora of cases where somebody squirrels away
a global's value in a local, and restores it on the way back out (at least doing
this in COMMON LISP could be reasonably safe because of unwind-protect, which
Standard LISP lacks). Of course, these have always been shallow binding
implementations, where specials come for nearly free. I'd rather not see globals
introduced into the language, but deep binding implementations may really need
them, and it would be better to have one, standard mechanism than have each
deep binding implementation define its own incompatible one.
+ Not only would it be nice to be able to copy things involving structures, it
would be nice to be able to walk an arbitrary LISP object, including going
through structures. As near as I can tell, there's no portable way to walk
through the slots of an arbitrary structure. For example, how could one write
a recursive function which counted the number of occurances of the symbol 'foo
in an arbitrary LISP object which might contain, at any level, arbitrary
structures? Have I missed something? I get the feeling that there may have been
a deliberate decision to not allow this, but I'm not sure why.
+ I'm sure I'm being dense, but could someone explain two things from GLS's
list of clarifications to me?
- Why does (tailp '() L) return nil? I would have expected it to always
return t (I think that means that I would have thought the second sentence
of the description was right, and the first sentence was incorrect).
- Why does xor with more than two arguments do the odd/even stuff? I would
have expected it either to look for exactly one true value or exactly one
false, but not something as random as an odd number of trues.
+ (-: The obvious way to have an all-purpose undo function is to generalize setf
to work with an odd number of arguments:
(setf (symbol-function 'foo)) => (undefun 'foo)
(setf (symbol-value '*foov*)) => (mkunbound '*foov*) :-)
- Don Morrison