Prev: lisp, java and evolution of types
Next: URGENT
From: Kaz Kylheku on 3 Nov 2009 20:36 On 2009-11-04, Kaz Kylheku <kkylheku(a)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))))))
From: Vassil Nikolov on 3 Nov 2009 21:44 On Tue, 03 Nov 2009 12:49:09 +0100, Nicolas Neuss <lastname(a)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?"
From: Kaz Kylheku on 3 Nov 2009 21:18 On 2009-11-04, Kaz Kylheku <kkylheku(a)gmail.com> wrote: > On 2009-11-04, Kaz Kylheku <kkylheku(a)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. This is quite cleaner now. [1]> (macroexpand '(update ((a (third x)) (b (fourth y))) (push 1 a) (push a b))) (LET ((#:G3126 X) (#:G3128 Y) (#:G3127 (THIRD #:G3126)) (#:G3129 (FOURTH #:G3128))) (SYMBOL-MACROLET ((A #:G3127) (B #:G3129)) (MULTIPLE-VALUE-PROG1 (PROGN (PUSH 1 A) (PUSH A B)) (SYSTEM::%RPLACA (CDDR #:G3126) #:G3127) (SYSTEM::%RPLACA (CDDDR #:G3128) #:G3129)))) ; 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 (,@(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.
From: budden on 5 Nov 2009 04:05 > 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.
From: Tobias C. Rittweiler on 9 Nov 2009 07:08
Madhu <enometh(a)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. -T. |