[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