* budden <9ffc6738-4b71-48e1-887f-1e100b094...@k19g2000yqc.googlegroups.com> : Wrote on Tue, 3 Nov 2009 02:26:38 -0800 (PST):
| (defmacro arg2f (function arg1 place &rest args) | `(setf ,place (,function ,arg1 ,place ,@args))) | | Maybe there is a good traditional name for arg1f already?
[Without endorsing this style]
See C-h f callf and C-h f callf2 in an Emacs near you.
,---- callf is a Lisp macro in `cl-macs.el'. | | (callf FUNC PLACE ARGS...) | | Set PLACE to (FUNC PLACE ARGS...). | FUNC should be an unquoted function name. PLACE may be a symbol, | or any generalized variable allowed by `setf'. `----
,---- callf2 is a Lisp macro in `cl-macs.el'. | | (callf2 FUNC ARG1 PLACE ARGS...) | | Set PLACE to (FUNC ARG1 PLACE ARGS...). | Like `callf', but PLACE is the second argument of FUNC, not the first. `----
> Maybe there is a good traditional name for arg1f already?
I have the following in my utilities:
(defmacro _f (op place &rest args) "Macro from @cite{(Graham 1993)}. Turns the operator @arg{op} into a modifying form, e.g. @code{(_f + a b) @equiv{} (incf a b)}." (multiple-value-bind (vars forms var set access) (get-setf-expansion place) `(let* (,@(mapcar #'list vars forms) (,(car var) (,op ,access ,@args))) ,set)))
>> Maybe there is a good traditional name for arg1f already?
> I have the following in my utilities:
> (defmacro _f (op place &rest args) > "Macro from @cite{(Graham 1993)}. Turns the operator @arg{op} into a > modifying form, e.g. @code{(_f + a b) @equiv{} (incf a b)}." > (multiple-value-bind (vars forms var set access) > (get-setf-expansion place) > `(let* (,@(mapcar #'list vars forms) > (,(car var) (,op ,access ,@args))) > ,set)))
_f is too cryptic, I think. What about 'modify-using?
Pascal Costanza <p...@p-cos.net> writes: > _f is too cryptic, I think. What about 'modify-using?
_f refers to the suffix "f" occurring in several CL operators with similar modifying behavior. So I think the name fits. And: since it appears in "On Lisp", I guess that there will be quite some people knowing it under this name.
(defmacro _2f (op arg1 place &rest args) "Like _f, but place is a second argument of op" (multiple-value-bind (vars forms var set access) (get-setf-expansion place) `(let* (,@(mapcar #'list vars forms) (,(car var) (,op ,arg1 ,access ,@args))) ,set)))
Nicolas Neuss wrote: > Pascal Costanza <p...@p-cos.net> writes:
>> _f is too cryptic, I think. What about 'modify-using?
> _f refers to the suffix "f" occurring in several CL operators with > similar modifying behavior. So I think the name fits. And: since it > appears in "On Lisp", I guess that there will be quite some people > knowing it under this name.
On Nov 3, 8:02 am, budden <budden-l...@mail.ru> wrote:
> Thanks all, I think _f satisfy me best as onLisp is an > important source of a tradition. It is a pity I didn't read > the book.
What's stopping you? It's well worth reading for several reasons, including Graham's idiosyncratic take on Common Lisp and (more relevantly to this thread) the excellent discussion of how to write fully general macros that modify SETFable places.
>> _f is too cryptic, I think. What about 'modify-using?
> _f refers to the suffix "f" occurring in several CL operators with > similar modifying behavior. So I think the name fits. And: since it > appears in "On Lisp", I guess that there will be quite some people > knowing it under this name.
> What bothers me most, is what if you want actually > (setf a (frob b (append c (nicate a) d) e)) ?
Then you actually write:
(setf a (frob b (append c (nicate a) d) e)) ?
There is no side effect if you evaluate a simple variable twice. In fact you can't avoid that. An update requires two accesses: read and write.
These ``F'' macros ensure that there are no additional redundant accesses. On the read access, the place is reduced to some object which can then be passed to a store form to update that place without any additional evaluation.
So the interesting case arises when we replace your A by some big expression:
(setf (BIG EXPR ...) (frob b (append c (nicate (BIG EXPR ...)) d) e)) ?
> (_f (frob b (append c _ d) e) (bar-accessor (session-value 'foo)))
> perhaps?
What you want is this:
(patternsdf-update (frob
(update ((var1 place1) (var2 place2) ... (varN placeN)) ... ... ... any number of forms involving var1 through varN as sources ... of values, as well as targets of assignments. ... ...)
UPDATE asserts that N places are to be updated. The bodies of the construct refer to the places using names var1 through varN. Each place is accessed without evaluating the place expression twice.
The update works like this, in the abstract semantics: prior to the execution of the body, the places are converted into load forms, which are accessed once to retrieve the values of the variables. The action in the body happens using the variables. When the body terminates, the update is committed using the corresponding store forms.
If the body terminates by a non-local exit, then the update is aborted. It's implementation-defined how many of the places have been accessed by that point (we'd like to be able to optimize by interleaving some of the accesses into the evaluation of the body, but no place is updated until the body terminates properly). The places are updated in order; if the store form for placeM terminates with a nonlocal exit, then places 1 thorugh M-1 are updated, but M through N are not updated.
In this form, the placeM expression can contain references to var1 through varM-1. This means that the evaluation of the places is interleaved with the establishment of the variable bindings.
So, how to express:
(setf (BIG EXPR ...) (frob b (append c (nicate (BIG EXPR ...)) d) e)) ?
(setf a (frob b (append c (nicate a) d) e))
Like this:
(update ((a (BIG EXPR ...))) (setf a (frob b (append c (nicate a) d) e)))
So here, it is understood that A is evaluated just once. It's easy to read: ``Do this update, where all occurence of A are understood to represent the place (BIG EXPR ...), such that (BIG EXPR ...) is evaluated only once.''
I could guess the meaning of this better than some obscure _F which cofuses the once-only semantics with a particular /way/ of treating a symbolic argument as a function and passing arguments to it.
I believe that it should be possible to implement UPDATE and UPDATE* with the pieces we have in Common Lisp.
Moreover, these macros could make it easy to write custom updater functions which avoid multiple evaluation, without having to know DEFINE-SETF-EXPANDER, and GET-SETF-EXPANSION.
On 2009-11-04, Kaz Kylheku <kkylh...@gmail.com> wrote:
> (update ((var1 place1) > (var2 place2) > ... > (varN placeN)) > ... > ... > ... any number of forms involving var1 through varN as sources > ... of values, as well as targets of assignments. > ... > ...)
First cut at update. Places cannot be multiple values (we take only the CAR of each list list of new values; see (car news) below).
[1]> (macroexpand '(update ((a (third x)) (b (fourth y))) (push 1 a) (push a b))) (LET (#:G3136 #:G3138 #:G3137 #:G3139 A B) (SETF #:G3136 X) (SETF #:G3138 Y) (SETF A (THIRD #:G3136)) (SETF B (FOURTH #:G3138)) (MULTIPLE-VALUE-PROG1 (PROGN (PUSH 1 A) (PUSH A B)) (SETF #:G3137 A) (SETF #:G3139 B) (SYSTEM::%RPLACA (CDDR #:G3136) #:G3137) (SYSTEM::%RPLACA (CDDDR #:G3138) #:G3139)))
Implementation:
(eval-when (:compile-toplevel :load-toplevel :execute) (defun collect-expansion-pieces (var-place-forms) (loop for (var place) in var-place-forms collect `(,var ,@(multiple-value-list (get-setf-expansion place)))))
(defmacro update (var-place-forms &body body) (loop for (var dummies vals news setter getter) in (collect-expansion-pieces var-place-forms) collecting var into all-vars appending dummies into all-dummies appending vals into all-vals collecting (car news) into all-news collecting setter into all-setters collecting getter into all-getters finally (return `(let (,@all-dummies ,@all-news ,@all-vars) ,@(mapcar (lambda (dummy val) `(setf ,dummy ,val)) all-dummies all-vals) ,@(mapcar (lambda (var getter) `(setf ,var ,getter)) all-vars all-getters) (multiple-value-prog1 (progn ,@body) ,@(mapcar (lambda (new var) `(setf ,new ,var)) all-news all-vars) ,@all-setters))))))
On Tue, 03 Nov 2009 12:49:09 +0100, Nicolas Neuss <lastn...@math.uni-karlsruhe.de> said:
> ... > (defmacro _f (op place &rest args) > "Macro from @cite{(Graham 1993)}. ..." > ...)
In my suitably humble opinion, and with all due respect, I believe that `_f' would be a suitable name either for a "demo" piece or the throwaway solution of an exercise, or _perhaps_ for something that is very frequently needed (which such a macro isn't).
Incidentally, I just came across a word in a book which stood out to me in the "context" of this thread: `bumpf'... (NB: not in the sense of "useless printed materials" (which I didn't know before anyway)).
---Vassil.
-- "Even when the muse is posting on Usenet, Alexander Sergeevich?"
> On 2009-11-04, Kaz Kylheku <kkylh...@gmail.com> wrote: >> (update ((var1 place1) >> (var2 place2) >> ... >> (varN placeN)) >> ... >> ... >> ... any number of forms involving var1 through varN as sources >> ... of values, as well as targets of assignments. >> ... >> ...)
> First cut at update. Places cannot be multiple values > (we take only the CAR of each list list of new values; > see (car news) below).
> [1]> (macroexpand '(update ((a (third x)) (b (fourth y))) (push 1 a) (push a b))) > (LET (#:G3136 #:G3138 #:G3137 #:G3139 A B) (SETF #:G3136 X) (SETF #:G3138 Y) > (SETF A (THIRD #:G3136)) (SETF B (FOURTH #:G3138)) > (MULTIPLE-VALUE-PROG1 (PROGN (PUSH 1 A) (PUSH A B)) (SETF #:G3137 A) > (SETF #:G3139 B) (SYSTEM::%RPLACA (CDDR #:G3136) #:G3137) > (SYSTEM::%RPLACA (CDDDR #:G3138) #:G3139)))
Second cut:
Now, the user-visible variables are symbol-macrolets which expand to the internal temporary variables used by the setf expander.
This lets us eliminate the silly hack whereby we evaluate the the getters into our variables, and then have to setf the values to the temporaries which are known to the store forms.
I've also rolled out the dummies and news setfs initialization into the LET, getting rid of yet more setfs.
(eval-when (:compile-toplevel :load-toplevel :execute) (defun collect-expansion-pieces (var-place-forms) (loop for (var place) in var-place-forms collect `(,var ,@(multiple-value-list (get-setf-expansion place)))))
(defmacro update (var-place-forms &body body) (loop for (var dummies vals news setter getter) in (collect-expansion-pieces var-place-forms) collecting var into all-vars appending dummies into all-dummies appending vals into all-vals collecting (car news) into all-news collecting setter into all-setters collecting getter into all-getters finally (return `(let (,@(mapcar #'list all-dummies all-vals) ,@(mapcar #'list all-news all-getters)) (symbol-macrolet (,@(mapcar #'list all-vars all-news)) (multiple-value-prog1 (progn ,@body) ,@all-setters)))))))
UPDATE* will need a different strategy. If the symbol macro strategy is to be retained, it will require nesting individual one-symbol symbol-macrolets among one-symbol lets.
It occurs to me, though, that we can do the symbol-macrolets the other way! That is to say, the gensyms returned by the GET-SETF-EXPANSION can be installed as symbol macrolets which route to the user's variables. Then we can generate a normal LET* to establish the user variables directly from the getter forms. The store form from the GET-SETF-EXPANSION will be fooled by our symbol macrolets into sucking the values directly out of our variables. Ha!
I think that the same body can be used for both, so that the only difference between UPDATE and UPDATE* will be the presence of either a LET and LET* in an otherwise identical template.
> In my suitably humble opinion, and with all due respect, I believe > that `_f' would be a suitable name either for a "demo" piece or the > throwaway solution of an exercise, or _perhaps_ for something that > is very frequently needed (which such a macro isn't).
I dislike _f either (and _2f is even worse as it is printed as |_2F|) but I believe Paul Grahams book is a source of tradition. Tradition is not always rational. It is strong not because it is rational, but because it is used by everyone.
budden <budden-l...@mail.ru> writes: > I dislike _f either (and _2f is even worse as it is printed as |_2F|) > but I believe Paul Grahams book is a source of tradition. Tradition is > not always rational. It is strong not because it is rational, but > because it is used by everyone.
Probably it would be best to have both _F and WITH-PLACES (Kaz' UPDATE with Rob's name) in some utility library like Alexandria. Then time would decide which is more useful to people. I think the answer would be: both.
Madhu <enom...@meer.net> writes: > * budden: > Wrote on Tue, 3 Nov 2009 02:26:38 -0800 (PST):
> | (defmacro arg2f (function arg1 place &rest args) > | `(setf ,place (,function ,arg1 ,place ,@args))) > | > | Maybe there is a good traditional name for arg1f already?
> [Without endorsing this style]
CALLF is nice as a _building block_ for modify macros; it's more powerfull than DEFINE-MODIFY-MACRO and at the same time it's conceptually simpler as you can just expand to it via DEFMACRO.
I think I posted an implementation a few months ago to comp.lang.lisp.