From: ··············@gmail.com
Subject: gensym / AllegroServe collision
Date: 
Message-ID: <1161412846.498950.294580@f16g2000cwb.googlegroups.com>
Hello list,

I've faced the following strange behaviour of ACL express 8.0 /
AllegroServe / SLIME (or probably just myself ;):

I've launched AllegroServe, evaluated the following code in SLIME's
repl:

(require 'aserve)
(use-package :net.aserve)
(use-package :net.html.generator)

(DEFUN TEST (REQUEST e)
         (WITH-HTTP-RESPONSE
          (REQUEST e :CONTENT-TYPE "text/html")
            (WITH-HTTP-BODY (REQUEST e)
              (HTML
               (:head (:TITLE "Test"))
	       (:p "this is just a test page")))))

(publish :path "/test" :function 'test)

and as expected, I got a nicely formatted page on the
http://localhost:2001/test

However, when I just replace ent with any value generated by gensym
(say, #:G1234) and evaluate resulted function:

(DEFUN TEST (REQUEST #:g1234)
         (WITH-HTTP-RESPONSE
          (REQUEST #:g1234 :CONTENT-TYPE "text/html")
            (WITH-HTTP-BODY (REQUEST #:g1234)
              (HTML
               (:head (:TITLE "Test"))
	       (:p "this is just a test page")))))

I received a blank page from Camino (and an error message from Safari).

Clarification: I started substituiting #:G1234 with 'e' and vice-versa
in order to debug define-url-function macro from PCL. I've modified it
to use allegro htmlgen instead of PCL macros, and it ceased to work,
and the problem was nailed down to the one described above.

What am I missing? Or, to phrase it in another way, what is missing
between my ears? I would appreciate any constructive feedback.

Best regards,
Victor.

PS. I have another question - how could one master
<strike>troll's</strike>more efficient language? It seems that adding
keywords like 'lame' or 'hell' or even 'CLISP' in a subject line yields
a number of replies from the group :), while my previous question
regarding free web development on mac resulted in only one answer :P

From: Bill Atkins
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <m24ptyw4e3.fsf@bertrand.local>
···············@gmail.com" <··············@gmail.com> writes:

> Hello list,
>
> I've faced the following strange behaviour of ACL express 8.0 /
> AllegroServe / SLIME (or probably just myself ;):
>
> I've launched AllegroServe, evaluated the following code in SLIME's
> repl:
>
> (require 'aserve)
> (use-package :net.aserve)
> (use-package :net.html.generator)
>
> (DEFUN TEST (REQUEST e)
>          (WITH-HTTP-RESPONSE
>           (REQUEST e :CONTENT-TYPE "text/html")
>             (WITH-HTTP-BODY (REQUEST e)
>               (HTML
>                (:head (:TITLE "Test"))
> 	       (:p "this is just a test page")))))
>
> (publish :path "/test" :function 'test)
>
> and as expected, I got a nicely formatted page on the
> http://localhost:2001/test
>
> However, when I just replace ent with any value generated by gensym
> (say, #:G1234) and evaluate resulted function:
>
> (DEFUN TEST (REQUEST #:g1234)
>          (WITH-HTTP-RESPONSE
>           (REQUEST #:g1234 :CONTENT-TYPE "text/html")
>             (WITH-HTTP-BODY (REQUEST #:g1234)
>               (HTML
>                (:head (:TITLE "Test"))
> 	       (:p "this is just a test page")))))
>
> I received a blank page from Camino (and an error message from Safari).
>
> Clarification: I started substituiting #:G1234 with 'e' and vice-versa
> in order to debug define-url-function macro from PCL. I've modified it
> to use allegro htmlgen instead of PCL macros, and it ceased to work,
> and the problem was nailed down to the one described above.
>
> What am I missing? Or, to phrase it in another way, what is missing
> between my ears? I would appreciate any constructive feedback.

The #: reader macro reads in an uninterned symbol.  This means that
#:bar and #:bar at two different places in a program will be read in
as two different symbols that just happen to have the same print-name.

What you're doing will never work.  The symbols need to be the same.
Why do you want to do this?
From: ··············@gmail.com
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <1161414053.292437.23850@f16g2000cwb.googlegroups.com>
> The #: reader macro reads in an uninterned symbol.  This means that
> #:bar and #:bar at two different places in a program will be read in
> as two different symbols that just happen to have the same print-name.

OK, got it.

> What you're doing will never work.  The symbols need to be the same.
> Why do you want to do this?

I was trying to debug a macro that used (gensym), which was behaving
strangely. In order to do that, I did macroexpand-1 and tried to
simplify and evaluate resulted code.

I assume I have to replace #:abcd with some normal symbol during
debugging - right? Or, to put it more generally, what is the best way
to debug macros?

Thanks for your help Bill,

Regards
Victor
From: Barry Margolin
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <barmar-F17E1D.03111121102006@comcast.dca.giganews.com>
In article <·······················@f16g2000cwb.googlegroups.com>,
 ···············@gmail.com" <··············@gmail.com> wrote:

> > The #: reader macro reads in an uninterned symbol.  This means that
> > #:bar and #:bar at two different places in a program will be read in
> > as two different symbols that just happen to have the same print-name.
> 
> OK, got it.
> 
> > What you're doing will never work.  The symbols need to be the same.
> > Why do you want to do this?
> 
> I was trying to debug a macro that used (gensym), which was behaving
> strangely. In order to do that, I did macroexpand-1 and tried to
> simplify and evaluate resulted code.
> 
> I assume I have to replace #:abcd with some normal symbol during
> debugging - right? Or, to put it more generally, what is the best way
> to debug macros?

Usually you just pretty-print the expansion, and check whether it looks 
like it should.  If you want to execute it, you can use EVAL.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Kalle Olavi Niemitalo
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <87bqo65al4.fsf@Astalo.kon.iki.fi>
Barry Margolin <······@alum.mit.edu> writes:

> In article <·······················@f16g2000cwb.googlegroups.com>,
>  ···············@gmail.com" <··············@gmail.com> wrote:
>
>> I assume I have to replace #:abcd with some normal symbol during
>> debugging - right? Or, to put it more generally, what is the best way
>> to debug macros?
>
> Usually you just pretty-print the expansion, and check whether it looks 
> like it should.  If you want to execute it, you can use EVAL.

One can also set or bind *PRINT-CIRCLE*, so that the first
occurrence of #:ABCD prints as #1=#:ABCD and the rest print as
#1#.  Then the reader will know to use the same uninterned symbol
in all places.

[7]> (progn (write (macroexpand-1 '(dotimes (x (car '(4))) (print x))) :circle t) (values))
(DO ((X 0 (1+ X)) (#1=#:G7649 (CAR '(4)))) ((>= X #1#) NIL) (PRINT X))

[8]> (DO ((X 0 (1+ X)) (#1=#:G7649 (CAR '(4)))) ((>= X #1#) NIL) (PRINT X))

0 
1 
2 
3 
NIL
[9]> 
From: Alan Crowe
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <86psck2v73.fsf@cawtech.freeserve.co.uk>
Barry Margolin <······@alum.mit.edu> writes:

> In article <·······················@f16g2000cwb.googlegroups.com>,
>  ···············@gmail.com" <··············@gmail.com> wrote:
> 
> > > The #: reader macro reads in an uninterned symbol.  This means that
> > > #:bar and #:bar at two different places in a program will be read in
> > > as two different symbols that just happen to have the same print-name.
> > 
> > OK, got it.
> > 
> > > What you're doing will never work.  The symbols need to be the same.
> > > Why do you want to do this?
> > 
> > I was trying to debug a macro that used (gensym), which was behaving
> > strangely. In order to do that, I did macroexpand-1 and tried to
> > simplify and evaluate resulted code.
> > 
> > I assume I have to replace #:abcd with some normal symbol during
> > debugging - right? Or, to put it more generally, what is the best way
> > to debug macros?
> 
> Usually you just pretty-print the expansion, and check whether it looks 
> like it should.  If you want to execute it, you can use EVAL.
                                          ^
                                          |
The interesting thing here is the ambiguity about the
referent of "it".

"it" could mean the expansion

"it" could mean the text that that REPL put on the screen to
show you the expansion.

The expansion is a data structure. You can capture it in a
variable. EVALing it works regardless of the state of
*print-circle* and the like because the data structure is
neither printed out nor read back in. For example:

Inspired by musical form we write an ABA macro that
generates a list of three items, the first run of the code,
the second run of the code, and finally the first run again.

CL-USER> (defmacro aba (form)
           (let ((temp (gensym)))
             `(let ((,temp ,form)) ;remember value of form
               (list ,temp ,form ,temp))))
ABA

CL-USER> (aba (random 1000))
(544 130 544)

Save the macroexpansion in a variable
CL-USER> (defparameter *expansion* (macroexpand '(aba (random 1000))))
*EXPANSION*

CL-USER> *expansion*
(LET ((#:G1597 (RANDOM 1000)))
  (LIST #:G1597 (RANDOM 1000) #:G1597))

Yes, that has caught it.

CL-USER> (eval *expansion*)
(699 114 699)

The data structure works. It is printing it out and reading
it back in that breaks it

CL-USER> (eval (read-from-string (format nil "~S" *expansion*)))

; In: LET ((#:G1551 #))

;   (LET (#)
;     (LIST #:G1551 # #:G1551))
; Note: Variable #:G1551 defined but never used.
; ; 

; Warning: These variables are undefined:
;   #:G1551 #:G1551
; 
; Evaluation aborted

Using ~A works because it drops the #: 
causing the reader to create a new symbol, |G1551|, in the
current package, and use it every time its name "G1551" is
encountered.

Using ~W with *print-circle* = t works because ~W uses #1=
and #1# to indicate structure sharing in a way that READ
understands.

You can "edit" the data structure with CL functions. For
debugging purposes we might want to wrap a print around the
(random 1000) to get extra output.

CL-USER> (eval (subst '(print (random 100)) '(random 1000) *expansion* :test #'equal))

29 
59 

(29 59 29)

I don't think I've ever done that for real. I think that I
tackle my macro writing in two steps and work from the
"other end".

The two steps are 

1)The macro function must process its arguments to generate
  the expansion. Does it do so correctly?

2)When the expansion is run it must do the right thing.

I start with 2, sorting out what I want the expansion to
be. Indeed sometimes my pattern is that the expansion
already exists in my code. When I am half way through typing
in a second version of the same code, ie I realise that I'm
repeating myself because different code needs wrapping in
the same boiler plate that I've typed in before, then I stop
and think. Maybe I should refactor my code by writing a
macro to generate the duplicate stuff once only?

So I'm clear early on what the expansion should be, and I
make sure that it does what I want before I move on to 1 and
try generating it. 

After I've written my defmacro I try expanding it with
purely schematic code. For example suppose I want ABA to
take a list of forms to be evaluated in an implicit progn. I
rewrite it:

CL-USER> (defmacro aba (&body code)
           (let ((temp (gensym)))
             `(let ((,temp (progn ,@code)))
               (list ,temp (progn ,@code) ,temp))))
ABA

This issue is whether I've put my progn's together with my
commas and comma-ats correctly. So I try

CL-USER> (macroexpand '(aba (f x y)(g u v)))
(LET ((#:G1607 (PROGN (F X Y) (G U V))))
  (LIST #:G1607 (PROGN (F X Y) (G U V)) #:G1607))
T

The argument (f x y)(g u v) is chosen to make it easy to
eyeball the macroexpansion. If it looks good I press on to
using runnable code, perhaps by typing in definitions 
for f and g :-)

At this stage it is still non-application code, merely
intended to exercise the macro-expansion.

By the time I use the macro with application code I expect
to have fully debugged it. If there are still bugs I judge
that I am wasting my time by not testing my macros enough
before using them. My theory is that it is much quicker to
debug macros that are wrapping test code than macros that
are wrapping application code.

Hmm, way back when I put quite a lot of work into "five
finger exercises" to make sure that I understood the When's
of defmacro. For example I wrote and played with this code
in 2003

(defmacro twice (x)
  (format t "Expanding twice with arg=~A~%" x)
  `(list ,x ,x))

(defun 2-times (x)
  (format t "Executing 2-times with arg=~A~%" x)
  (list x x))

(defun use-twice(y)
  (list
   (twice y)
   (twice (list y y))))

(defun use-2-times(y)
  (list 
   (2-times y)
   (2-times (list y y))))

These are toys to be played with, not examples to be
described.

Alan Crowe
Edinburgh
Scotland
From: Pascal Bourguignon
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <8764eexeyt.fsf@thalassa.informatimago.com>
···············@gmail.com" <··············@gmail.com> writes:

>> The #: reader macro reads in an uninterned symbol.  This means that
>> #:bar and #:bar at two different places in a program will be read in
>> as two different symbols that just happen to have the same print-name.
>
> OK, got it.
>
>> What you're doing will never work.  The symbols need to be the same.
>> Why do you want to do this?
>
> I was trying to debug a macro that used (gensym), which was behaving
> strangely. In order to do that, I did macroexpand-1 and tried to
> simplify and evaluate resulted code.
>
> I assume I have to replace #:abcd with some normal symbol during
> debugging - right? Or, to put it more generally, what is the best way
> to debug macros?

If you want to enter back parts of the macro expansion, yes, it might
be prudent to remove the #: before.

In other cases, you can just (setf *print-circle* t)
(Put it in your rc file!)


[714]> (let ((ve (gensym "ENTITY-"))) 
         `(DEFUN TEST (REQUEST ,ve)
            (WITH-HTTP-RESPONSE
                (REQUEST ,ve :CONTENT-TYPE "text/html")
              (WITH-HTTP-BODY (REQUEST ,ve)
                (HTML
                  (:head (:TITLE "Test"))
                  (:p "this is just a test page"))))))
(DEFUN TEST (REQUEST #1=#:ENTITY-13659)
 (WITH-HTTP-RESPONSE (REQUEST #1# :CONTENT-TYPE "text/html")
  (WITH-HTTP-BODY (REQUEST #1#)
   (HTML (:HEAD (:TITLE "Test")) (:P "this is just a test page")))))
[715]> (DEFUN TEST (REQUEST #1=#:ENTITY-13659)
 (WITH-HTTP-RESPONSE (REQUEST #1# :CONTENT-TYPE "text/html")
  (WITH-HTTP-BODY (REQUEST #1#)
   (HTML (:HEAD (:TITLE "Test")) (:P "this is just a test page")))))
TEST
[716]> 



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

PUBLIC NOTICE AS REQUIRED BY LAW: Any use of this product, in any
manner whatsoever, will increase the amount of disorder in the
universe. Although no liability is implied herein, the consumer is
warned that this process will ultimately lead to the heat death of
the universe.
From: Sidney Markowitz
Subject: Re: gensym / AllegroServe collision
Date: 
Message-ID: <453a2239$0$88664$742ec2ed@news.sonic.net>
··············@gmail.com wrote, On 21/10/06 8:00 PM:
> I assume I have to replace #:abcd with some normal symbol during
> debugging - right? Or, to put it more generally, what is the best way
> to debug macros?

If you bind *print-circle* to T then the gensyms will print out in a way
that can be read back in.

 (let ((*print-circle* t)) (let ((x (gensym))) (pprint (list x x))))

prints out

 (#1=#:G1733 #1#)

-- 
    Sidney Markowitz
    http://www.sidney.com