From: Chaitanya Gupta
Subject: Dynamic bindings for *macroexpand-hook*
Date: 
Message-ID: <ek11j6$rp2$1@registered.motzarella.org>
Hello,

I want macroexpand-1 to behave in such a way that all gensyms should be 
referenced by #n=, #n#. When I set *print-circle* to t, it works fine.

(defmacro useless (foo)
   (let ((bar (gensym)))
     `(defun ,foo (,bar)
        (list ,bar))))


 > (macroexpand-1 '(useless foo))
(DEFUN FOO (#:G1325) (LIST #:G1325))
T

 > (setf *print-circle* t)
T

 > (macroexpand-1 '(useless foo))
(DEFUN FOO (#1=#:G1326) (LIST #1#))
T


However, I want a macroexpand hook function which will do so regardless 
of the "global" value of *print-circle*. So I try something like this -

(defun my-hook (expander form env)
   (let ((*print-circle* t))
     (funcall expander form env)))


 > (setf *macroexpand-hook* 'my-hook)
MY-HOOK

But this doesn't work.

 > (setf *print-circle* nil)
NIL

 > (macroexpand-1 '(useless foo))
(DEFUN FOO (#:G1337) (LIST #:G1337))
T


Setting *print-circle* back to t works.


 > (setf *print-circle* t)
T

 > (macroexpand-1 '(useless foo))
(DEFUN FOO (#1=#:G1338) (LIST #1#))
T

Where am I going wrong?
Also, the SLIME command slime-macroexpand-1 doesn't reference gensyms 
this way even when *print-circle* is t. Any pointers on how to make it work?

Thanks,
Chaitanya

From: Pascal Bourguignon
Subject: Re: Dynamic bindings for *macroexpand-hook*
Date: 
Message-ID: <87d57fwx4a.fsf@thalassa.informatimago.com>
Chaitanya Gupta <ยทยทยทยท@chaitanyagupta.com> writes:
> I want macroexpand-1 to behave in such a way that all gensyms should
> be referenced by #n=, #n#. When I set *print-circle* to t, it works
> fine.
> 
> However, I want a macroexpand hook function which will do so
> regardless of the "global" value of *print-circle*. So I try something
> like this -
>
> (defun my-hook (expander form env)
>   (let ((*print-circle* t))
>     (funcall expander form env)))
>
>
>> (setf *macroexpand-hook* 'my-hook)
> MY-HOOK
>
> But this doesn't work.
>
>> (setf *print-circle* nil)
> NIL
>
>> (macroexpand-1 '(useless foo))
> (DEFUN FOO (#:G1337) (LIST #:G1337))
> T
>
> Setting *print-circle* back to t works.
>
>> (setf *print-circle* t)
> T
>
>> (macroexpand-1 '(useless foo))
> (DEFUN FOO (#1=#:G1338) (LIST #1#))
> T
>
> Where am I going wrong?
> Also, the SLIME command slime-macroexpand-1 doesn't reference gensyms
> this way even when *print-circle* is t. Any pointers on how to make it
> work?

The flags named *print-<something>* are used by the lisp printer.
(The flags named *read-<something>* are used by the lisp reader.)

Where did you print anything?

The REPL is a (loop (print (eval (read))))
With *PRINT-CIRCLE* set to NIL, 
You type (macroexpand-1 '(useless foo)) at this repl, so you substitute:

    (loop (print (eval '(macroexpand-1 '(useless foo)))))

Which will eventually reduce to:

    (loop (print (let ((*print-circle* t)) (funcall expander form env))))

So, lisp dutifully binds T to *PRINT-CIRCLE* for the dynamic scope of
the expander function call.  And this expander function doesn't print
anything and return the macro expansion:

    (loop (print '(DEFUN FOO (#:G1337) (LIST #:G1337))))

So it get printed with *PRINT-CIRCLE* still set to NIL.



Either set *print-circle* globally (there's no problem with that), or
print from the hook:

(defun my-hook (expander form env)
   (let ((*print-circle* t))
     (print (funcall expander form env))))

> (let ((*macroexpand-hook* (function my-hook)))
    (macroexpand-1 '(useless foo)))
(DEFUN FOO (#1=#:G1326) (LIST #1#))       ; printed by the hook
(DEFUN FOO (#:G1325) (LIST #:G1325))      ; returned and printed by the REPL
T                                         ; returned and printed by the REPL

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
        Un chat errant
se soulage
        dans le jardin d'hiver
                                        Shiki
From: Chaitanya Gupta
Subject: Re: Dynamic bindings for *macroexpand-hook*
Date: 
Message-ID: <ek1fag$8ps$1@registered.motzarella.org>
Pascal Bourguignon wrote:
> 
> The REPL is a (loop (print (eval (read))))
> With *PRINT-CIRCLE* set to NIL, 
> You type (macroexpand-1 '(useless foo)) at this repl, so you substitute:
> 
>     (loop (print (eval '(macroexpand-1 '(useless foo)))))
> 
> Which will eventually reduce to:
> 
>     (loop (print (let ((*print-circle* t)) (funcall expander form env))))
> 
> So, lisp dutifully binds T to *PRINT-CIRCLE* for the dynamic scope of
> the expander function call.  And this expander function doesn't print
> anything and return the macro expansion:
> 
>     (loop (print '(DEFUN FOO (#:G1337) (LIST #:G1337))))
> 
> So it get printed with *PRINT-CIRCLE* still set to NIL.
> 
> 

That clears it up. Thanks.

My main problem was that slime-macroexpand-1, by default, didn't have 
#n= => #n# referencing (what is it called?) on. I thought a custom 
macroexpand hook would solve the problem. But, armed with the knowledge 
above, I dug into SWANK/SLIME code and found this out -

CL-USER> swank:*macroexpand-printer-bindings*
((*PRINT-CIRCLE*) (*PRINT-PRETTY* . T) (*PRINT-ESCAPE* . T)
  (*PRINT-LEVEL*) (*PRINT-LENGTH*))

Setting cdr of (*PRINT-CIRCLE*) to T does the job. :)

Chaitanya
From: Kaz Kylheku
Subject: Re: Dynamic bindings for *macroexpand-hook*
Date: 
Message-ID: <1164311943.896838.23340@f16g2000cwb.googlegroups.com>
Chaitanya Gupta wrote:
> Hello,
>
> I want macroexpand-1 to behave in such a way that all gensyms should be
> referenced by #n=, #n#.

This doesn't make sense. #n= is a print notation, which has nothing to
do with the semantics of macroexpand.

It has to do with how the results of macroexpand-1 are /printed/.

>  > (macroexpand-1 '(useless foo))
> (DEFUN FOO (#1=#:G1326) (LIST #1#))
> T
>
>
> However, I want a macroexpand hook function which will do so regardless
> of the "global" value of *print-circle*.

But the printing is done by your listener, not by macroexpand-1.
(That's what the P stands for in REPL).

So it's the binding of *PRINT-CIRCLE* that is evident in your listener
which determines how the result of the evaluation is printed.

> So I try something like this -
>
> (defun my-hook (expander form env)
>    (let ((*print-circle* t))
>      (funcall expander form env)))


But the (FUNCALL EXPANDER ...) form does not print anything. It
produces a data structure which is returned out of the LET and out of
MY-HOOK to the caller.
From: Chaitanya Gupta
Subject: Re: Dynamic bindings for *macroexpand-hook*
Date: 
Message-ID: <ek6726$bel$1@registered.motzarella.org>
Kaz Kylheku wrote:
> This doesn't make sense. #n= is a print notation, which has nothing to
> do with the semantics of macroexpand.
> 
> It has to do with how the results of macroexpand-1 are /printed/.
> 

Yes. I have understood now what was happening (Pascal's reply made it 
quite clear).

Thanks,

Chaitanya