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

Re: SETF of APPLY



I like Guy's new text much more than the existing page 96, and after
reading Moon's code I believe it almost states the criterion for a
setf-applyable function correctly.  The problem is that it obscures
with faint emphasis its major point.  I read the statement:

    The SETF method for the function <name> must be such that the
    expansion of

    (SETF (<name> <z1> <z2> ... <zn> <zrest>) <z0>)

    uses the form <zrest> (or the generated variable that fronts for it)
    only as the last argument in some number of function calls

    (<any-function> <q1> ... <qn> <zrest>)			<1>

as the definition for a setf-applyable function, and the statement

    Every such function call in the expansion is altered to be

    (APPLY #'<any-function> <q1> ... <qn> <zrest>)		<2>

as the beginning of an explanation of what it does.  But by examining
the code I realize that the latter statement is the main point:  that
when those forms <1> get alterated to <2> their semantics must change
analogously to the alteration of

(<name> <x1> <x2> ... <xn> <zrest>)

to

(APPLY #'<name> <x1> <x2> ... <xn> <zrest>)

or the SETF will do something bizarre.  For instance, if <any-function>
has <n+1> required arguments and <zrest> turns out to be NIL, the
expansion will be in error.

Forgive the impulsive radicality of a neophyte but I think this
restriction needs an explanation that is not feasible until SETF
methods are introduced.  I would much rather see page 96 say something
like

    o A call to APPLY of the form (APPLY #'<name> {arg}* <others>)
      where <name>, has a ``SETF method'' amenable to APPLY, as
      described at the end of this section.  The only functions whose
      SETF expansions are defined by Common Lisp to have this form are
      AREF, BIT, and SBIT.

      As an example, suppose that the variable INDEXES ....

Then somewhere around page 106 the real bag of worms can be dumped on
the table:

    When

    (APPLY #'<name> <x1> <x2> ... <xn> <rest>)

    is used as a generalized variable, the SETF method for APPLY will
    access the SETF method for <name> with exactly <n+1> arguments:

    (GET-SETF-METHOD '(<name> <x1> <x2> ... <xn> <zrest>))

    that is, with the final argument to APPLY--and thus a list of final
    arguments to <name>--replaced by a single final argument to <name>.
    The storing and accessing forms returned by the SETF method must
    refer to the temporary variable <temp-rest> corresponding to <zrest>
    only as the last argument to a function:

    (<func> <q1> <q2> ... <qm> <temp-rest>)

    Each such function call will be altered when used in the SETF
    method of APPLY to be

    (APPLY #'<func> <q1> <q2> ... <qm> <temp-rest>)

    replacing the final argument to <func> by a list of final arguments.
    For (APPLY #'<name> <x1> <x2> ... <xn> <rest>) to be used as a
    generalized variable to be meaningful, the transformation
    described above must produce a correct SETF method for it.

I think it important that <x1> ... <xn> be guaranteed to be passed
verbatim in case their structure matters.

It might help to put the actual code for the APPLY SETF method in.

Further desiderata:

I wish there were some way for the author to declare that a SETF method
is or is not amenable to APPLY, and for a SETF method to determine
whether it is expanding for APPLY.  This might be done by promising
that APPLY's SETF method will use `(:MORE-ARGS ,(gensym)) for <zrest>
above.

Shouldn't <name>'s SETF method to be restricted to at most <n> required
and optional arguments, modulo destructuring?  Should

	(SETF (APPLY #'AREF (CONS FOO INDEXES)) NEWVALUE)

be allowed, or should it be required to be written

	(SETF (APPLY #'AREF FOO INDEXES) NEWVALUE)

as on page 97?  As it is, the code apparently works for the former only
by the accident that the SETF method for AREF could be (or is?) defined
with only an &REST argument:

	(DEFINE-SETF-METHOD AREF (&REST AREF-FORM)
	  (LET ((STORE (GENSYM))
		(AREF-FORM-TEMP (LOOP FOR ARGUMENT IN AREF-FORM
				      COLLECT (GENSYM))))
	     (VALUES AREF-FORM-TEMP
	     	     AREF-FORM
		     (LIST STORE)
		     `(ASET ,STORE ,@AREF-FORM-TEMP)
		     `(AREF ,@AREF-FORM-TEMP))))

Dan