Lisp HUG Maillist Archive

Question about DEFINE-MODIFY-MACRO

Hi, LispWorks

Say given following DEFINE-MODIFY-MACRO definition:

(DEFINE-MODIFY-MACRO XXX-MODIFY-MACRO-USING-TEST (XXX-PUSHNEW XXX- 
PUSHNEW-TEST XXX-PUSHNEW-KEY)
                      XXX-PUSHNEW-FUNCTION-USING-TEST)

When I try to do (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL  
NIL)), almost every CL give me results like this:

CL-USER(2): (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL NIL))
(LET* ((#:G100 (XXX-PUSHNEW-FUNCTION-USING-TEST A 0 'EQL NIL)))
   (SETQ A #:G100))
T

Above happens on Allegro CL, and results from SBCL, Clozure CL are  
almost the same. But LispWorks give me following result:

CL-USER 1 > (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL NIL))
(LET* ()
   (LET* ((#:|following-form3994| 0) (#:|following-form3995| 'EQL) (#:| 
following-form3996| NIL))
     (LET ((#:G3993
            (XXX-PUSHNEW-FUNCTION-USING-TEST A
                                             #:|following-form3994|
                                             #:|following-form3995|
                                             #:|following-form3996|)))
       (SETQ A #:G3993))))
T

When XXX-PUSHNEW-FUNCTION-USING-TEST is NOT a function but macro, the  
macro expansion which generated by LispWorks break my code ...

So I want to ask:

1) Is that legal if I use a macro symbol on DEFINE-MODIFY-MACRO's last  
argument?

or

2) Is the behavior of LW's DEFINE-MODIFY-MACRO right?

Thanks very much!!

---
Chun Tian (binghe)


Re: Question about DEFINE-MODIFY-MACRO

Unable to parse email body. Email id is 9029

Re: Question about DEFINE-MODIFY-MACRO

Hi, Martin

To produce the same results with other CL implementations WHEN the eval order is relevent, I think out following solution:

(defmacro my-define-modify-macro
          (name lambda-list function &rest doc-string-and-declarations)
  `(progn
     (define-modify-macro
         ,name ,lambda-list ,function ,@doc-string-and-declarations)
     #+lispworks
     (define-compiler-macro ,name
         (&whole form var &rest args)
       (if (every #'(lambda (x) (or (atom x)
                                    (eq 'quote (car x))))
                  args)
           (let ((temp (gensym)))
             `(let ((,temp (,',function ,var ,@args)))
                (setq ,var ,temp)))
         form))))

That is: for atom and quote arguments, just don't use LW's DEFINE-MODIFY-MACRO. Now, I got following results:

CL-USER 14 > (funcall (compiler-macro-function 'xxx-modify-macro-using-test)
 '(xxx-modify-macro-using-test a 0 'eql nil) nil)

(LET ((#:G940 (XXX-PUSHNEW-FUNCTION-USING-TEST A 0 (QUOTE EQL) NIL))) (SETQ A #:G940))

CL-USER 15 > (funcall (compiler-macro-function 'xxx-modify-macro-using-test)
 '(xxx-modify-macro-using-test a 0 (setq a b) nil) nil)

(XXX-MODIFY-MACRO-USING-TEST A 0 (SETQ A B) NIL)

Do you think this will work?

Regards,

Chun Tian (binghe)

On Sat, Mar 14, 2009 at 5:32 AM, Martin Simmons <martin@lispworks.com> wrote:

>>>>> On Fri, 13 Mar 2009 00:56:32 +0800, Chun Tian (binghe) said:
>
> Hi, LispWorks
>
> Say given following DEFINE-MODIFY-MACRO definition:
>
> (DEFINE-MODIFY-MACRO XXX-MODIFY-MACRO-USING-TEST (XXX-PUSHNEW XXX-
> PUSHNEW-TEST XXX-PUSHNEW-KEY)
>                       XXX-PUSHNEW-FUNCTION-USING-TEST)
>
> When I try to do (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL
> NIL)), almost every CL give me results like this:
>
> CL-USER(2): (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL NIL))
> (LET* ((#:G100 (XXX-PUSHNEW-FUNCTION-USING-TEST A 0 'EQL NIL)))
>    (SETQ A #:G100))
> T
>
> Above happens on Allegro CL, and results from SBCL, Clozure CL are
> almost the same. But LispWorks give me following result:
>
> CL-USER 1 > (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL NIL))
> (LET* ()
>    (LET* ((#:|following-form3994| 0) (#:|following-form3995| 'EQL) (#:|
> following-form3996| NIL))
>      (LET ((#:G3993
>             (XXX-PUSHNEW-FUNCTION-USING-TEST A
>                                              #:|following-form3994|
>                                              #:|following-form3995|
>                                              #:|following-form3996|)))
>        (SETQ A #:G3993))))
> T
>
> When XXX-PUSHNEW-FUNCTION-USING-TEST is NOT a function but macro, the
> macro expansion which generated by LispWorks break my code ...
>
> So I want to ask:
>
> 1) Is that legal if I use a macro symbol on DEFINE-MODIFY-MACRO's last
> argument?

I don't think ANSI specifies what forms appear in the expansion, though it
does specify order of evaluation (see below).


> or
>
> 2) Is the behavior of LW's DEFINE-MODIFY-MACRO right?

Yes and I suspect other implementations are slightly wrong.  Consider the
following:

(defun radjoin (list value)
 (adjoin value list))

(define-modify-macro rpushnew (value) radjoin)

(let ((the-list (list 1 2)))
 (rpushnew the-list (setq the-list (list 4 5)))
 the-list)

According to ANSI 5.1.3
http://www.lispworks.com/documentation/HyperSpec/Body/05_ac.htm, the
evaluation proceeds in 6 steps.  For the above example, the steps should be
like this:

1. Skipped (there are no preceding-forms).
2. Skipped (there are no subforms of the place the-list).
3. Evaluate the following-form (setq the-list (list 4 5)).
4. Read the-list, giving (4 5).
5. Compute the new value from (radjoin (4 5) (4 5)), giving ((4 5) 4 5).
6. Store ((4 5) 4 5) into the-list.

--
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/




--
Chun Tian (binghe)
NetEase.com, Inc.

Re: Question about DEFINE-MODIFY-MACRO

Unable to parse email body. Email id is 9151

Updated at: 2020-12-10 08:41 UTC