Page 1 of 1

gensym's behavior in a macro

PostPosted: Sun Dec 02, 2012 6:46 am
by megera
HI
I have a fast & easy question(easy for You ) about gensym used in that macro example:

Code: Select all
(defmacro for (var start stop &body body)
      (let ((gstop (gensym)))
        `(do ((,var ,start (1+ ,var))
              (,gstop ,stop))
             ((> ,var ,gstop))
         ,@body)))

>(for x 1 5 (princ  x)))
12345
NIL   


But if I redefine ‘do test ‘as : (> ,var ,stop) instead of (> ,var ,gstop) for demonstration purposes only:

Code: Select all
(defmacro for (var start stop &body body)
      (let ((gstop (gensym)))
        `(do ((,var ,start (1+ ,var))
              (,gstop ,stop))
             ((> ,var ,stop))  ;; here
           ,@body)))

;;why macro call:
(for x 1 5 (princ  x)))  ; return only -> NIL?


if I see it expanded:
(pprint (macroexpand-1 '(for x 1 5 (princ x)))) return -> (DO ((X 1 (1+ X))) ((> X 5)) (PRINC X))

it should work equally…..???why “do body” is not valued? Only because gensym’s variable is unused?? :?
thanks in advance!

Re: gensym's behavior in a macro

PostPosted: Sun Dec 02, 2012 7:15 am
by Goheeca
I get the same output + a warning about an unused variable, but it doesn't work equally. Look at this:
Code: Select all
(defmacro for (var start stop &body body)
  `(do ((,var ,start (1+ ,var))
        (stop-cond ,stop))
       ((> ,var stop-cond))
     ,@body))

stop will be evaluated only once and the result will be saved into the stop-cond, but we've captured stop-cond (we can't reach hypotetical outer stop-cond defined in let which is wrapping our for), hence we create gstop which its value is a unique generated symbol and unquote it at appropriate places where stop-cond was used.

Re: gensym's behavior in a macro

PostPosted: Sun Dec 02, 2012 8:05 am
by megera
HI Goheeca and thankf for your help!
Ok I understand reason to use gensym in macro , but yet it is not clear to me why using *,stop* instead *gstop*(gensym variable) in *do* test conditions return NIL..
For example You said that *,stop* will be evaluated only once, but if I ridefine *for* macro in this way and without use gensym expr, it’ll works as I expect:

Code: Select all
(defmacro for (var start stop &body body)
        `(do ((,var ,start (1+ ,var)))
             ((> ,var ,stop))
            (progn
               ,@body
               (princ ,stop))))

1525354555
NIL


now ,stop will be evalutated for each iteration….but why if I define a gensym var this does not happen??? :? :?
thanks again for your patience.. :mrgreen:

Re: gensym's behavior in a macro

PostPosted: Sun Dec 02, 2012 8:27 am
by Goheeca
I've get this:
Code: Select all
* (defmacro for (var start stop &body body)
     (let ((gstop (gensym)))
         `(do ((,var ,start (1+ ,var))
               (,gstop ,stop))
              ((> ,var ,stop))
            ,@body)))

FOR
* (for x 1 5 (princ x))
; in: FOR X
;     (LET ((X 1) (#:G741 5))
;       (TAGBODY
;         (GO #:G743)
;        #:G742
;         (TAGBODY (PRINC X))
;         (PSETQ X (1+ X))
;        #:G743
;         (UNLESS (> X 5) (GO #:G742))
;         (RETURN-FROM NIL (PROGN))))
;
; caught STYLE-WARNING:
;   The variable #:G741 is defined but never used.
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
12345
NIL
* (dribble)

you can see that it works. That returned nil is a value of result-form which was omitted in this case.

Re: gensym's behavior in a macro

PostPosted: Sun Dec 02, 2012 8:41 am
by megera
THANKS!! :D

Re: gensym's behavior in a macro

PostPosted: Mon Dec 03, 2012 2:15 pm
by pjstirling
When you have a misbehaving macro you should use MACROEXPAND to see that it is expanding to what you want it to. If you use emacs+slime, then you can put the cursor at the opening paren of the form and then typing C-c return

Re: gensym's behavior in a macro

PostPosted: Tue Dec 04, 2012 3:50 am
by megera
Thanks pjstirling ;)