From: Johan Ur Riise
Subject: uninterned symbols used as names in macros - where are they kept?
Date: 
Message-ID: <87y7thyjoq.fsf@morr.riise-data.net>
Just curious.

I RTFHS "3.2.1 Compiler Terminology", but didn't "get" it.

When I compile a macro like this:

CL-USER> (defmacro m ()
  (let ((s (gensym)))
    `(let ((,s 2))
       ,s)))
M

I can use it without problem like this:

CL-USER> (m)
2

but if I expand it

CL-USER> (macroexpand '(m))
(LET ((#:G941 2))
  #:G941)
T

and then use the expanded form directly *) see below

CL-USER> (LET ((#:G941 2))
  #:G941)

I get an error:

The variable #:G941 is unbound.
   [Condition of type UNBOUND-VARIABLE]

This is understandable, as the symbol is uninterned. But the first
question is

1. How come this works when the macro is used normally, where is
the symbol kept?

When I use slime, I can copy the result from the macro-expansion
using up-arrow, then <RET>, this copies the form down to the REPL.
Then a new <RET> to evaluate it. Note: The form is coloured red
before and after the copy. Point is, in this case the form actually
evaluates to 2 as in the (m) case above.

2. Does slime keep the uninterned symbol, or maybe the whole
macroexpansion as an object somewhere?

*) to be able to get the macroexpansion as a string (in slime
repl), I actually had to evaluate (print *).

From: David Golden
Subject: Re: uninterned symbols used as names in macros - where are they kept?
Date: 
Message-ID: <faoGg.12916$j7.325437@news.indigo.ie>
Johan Ur Riise wrote:

> 
> Just curious.
> 
> I RTFHS "3.2.1 Compiler Terminology", but didn't "get" it.
> 
> When I compile a macro like this:
> 
> CL-USER> (defmacro m ()
>   (let ((s (gensym)))
>     `(let ((,s 2))
>        ,s)))
> M
> 
> I can use it without problem like this:
> 
> CL-USER> (m)
> 2
> 
> but if I expand it
> 
> CL-USER> (macroexpand '(m))
> (LET ((#:G941 2))
>   #:G941)
> T
> 
> and then use the expanded form directly *) see below
> 
> CL-USER> (LET ((#:G941 2))
>   #:G941)
> 
> I get an error:
> 
> The variable #:G941 is unbound.
>    [Condition of type UNBOUND-VARIABLE]
> 
> This is understandable, as the symbol is uninterned. But the first
> question is
> 
> 1. How come this works when the macro is used normally, where is
> the symbol kept?
>

Well, um, it's in s for one thing...?

Someone else will doubtless explain this far better than me, but:
in the macro case, it's the *same* single uninterned symbol being used,
because of the backquote substitution of the value of s. 
in the direct entry case, the reader is creating a fresh uninterned
symbol each time it sees the "make me an uninterned symbol" construct #:
- the first #:G941 and the second #:G941 are therefore different
uninterned symbol objects in the second case, they'd just have equal
symbol-name "slots", whereas the gensym is returning a single
uninterned symbol in the macro case, it's being stored in s, and the
backquote substitution is using it twice. 

Try this direct entry, which uses the circular reference reader
construct to achieve something similar to the macro, and works in SBCL
anyway (not sure of the strict standards-legalities of it, but hey):

CL-USER> (let ((#1=#:XYZZY 2)) #1#)

There, clear as mud :-)


 
From: Johan Ur Riise
Subject: Re: uninterned symbols used as names in macros - where are they kept?
Date: 
Message-ID: <87r6z9y3nl.fsf@morr.riise-data.net>
David Golden <············@oceanfree.net> writes:
and
Pascal Costanza <··@p-cos.net> writes:

Great, I think I understand now. Thanks.
From: Pascal Bourguignon
Subject: Re: uninterned symbols used as names in macros - where are they kept?
Date: 
Message-ID: <87irklaugy.fsf@thalassa.informatimago.com>
Johan Ur Riise <·····@riise-data.no> writes:

> David Golden <············@oceanfree.net> writes:
> and
> Pascal Costanza <··@p-cos.net> writes:
>
> Great, I think I understand now. Thanks.

You can put:

   (setf *print-circle* t)

in your ~/.${IMPLEMENTATION}rc.lisp

(CL mandates NIL as default, but for newbies and most interactive use,
T is a better choice.)

Then you see immediately what you really have:


[565]> (defmacro m ()
  (let ((s (gensym)))
    `(let ((,s 2))
       ,s)))
M
[566]> (m)
2
[567]> (macroexpand '(m))
(LET ((#1=#:G93839 2)) #1#) ;
T
[568]> (LET ((#1=#:G93839 2)) #1#)         ; copy/pasted
2




-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

This universe shipped by weight, not volume.  Some expansion may have
occurred during shipment.
From: Pascal Costanza
Subject: Re: uninterned symbols used as names in macros - where are they kept?
Date: 
Message-ID: <4kugj9Fe0o27U1@individual.net>
Johan Ur Riise wrote:
> Just curious.
> 
> I RTFHS "3.2.1 Compiler Terminology", but didn't "get" it.
> 
> When I compile a macro like this:
> 
> CL-USER> (defmacro m ()
>   (let ((s (gensym)))
>     `(let ((,s 2))
>        ,s)))
> M
> 
> I can use it without problem like this:
> 
> CL-USER> (m)
> 2
> 
> but if I expand it
> 
> CL-USER> (macroexpand '(m))
> (LET ((#:G941 2))
>   #:G941)
> T
> 
> and then use the expanded form directly *) see below
> 
> CL-USER> (LET ((#:G941 2))
>   #:G941)
> 
> I get an error:
> 
> The variable #:G941 is unbound.
>    [Condition of type UNBOUND-VARIABLE]
> 
> This is understandable, as the symbol is uninterned.

The reason is not primarily because the symbol is uninterned, the reason 
is primarily because the form #:G941 is read twice. Since #:G941 denotes 
an uninterned symbol, the reader cannot (actually must not) find it when 
it is read the second time, so the reader produces two different symbols 
(which just happen to have the same symbol-name).

> But the first question is
> 
> 1. How come this works when the macro is used normally, where is
> the symbol kept?

It works because the forms generated by macros are typically not re-read 
(that would be stupid). When the macro is used "normally", what the 
macro generates is an s-expression. An s-expression is a data structure 
that includes, among other things, references to possibly uninterned 
symbols. Since your macro generates _one_ uninterned symbol and inserts 
that same symbol in two different places in the s-expression, and since 
the s-expression keeps references to those symbols and not their names, 
it is clear that the resulting s-expression simply refers twice to the 
same symbol. Essentially, Lisp s-expressions rely on symbol identities / 
object identities to determine the meaning of symbols, not their names 
(= values).

> When I use slime, I can copy the result from the macro-expansion
> using up-arrow, then <RET>, this copies the form down to the REPL.
> Then a new <RET> to evaluate it. Note: The form is coloured red
> before and after the copy. Point is, in this case the form actually
> evaluates to 2 as in the (m) case above.
> 
> 2. Does slime keep the uninterned symbol, or maybe the whole
> macroexpansion as an object somewhere?

IIRC, the copy operations in SLIME respect object identity, and do not 
cause forms to be re-read. This would explain why it apparently works.


Pascal

> *) to be able to get the macroexpansion as a string (in slime
> repl), I actually had to evaluate (print *).


-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/