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
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
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
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.
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