From: Kaz Kylheku on
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

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
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
>   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
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.
First  |  Prev  | 
Pages: 1 2 3
Prev: lisp, java and evolution of types
Next: URGENT