From: fortunatus
Subject: Macro Writing Question #2
Date: 
Message-ID: <015ba0a1-6091-4e60-abd9-5a0c3a598887@a12g2000pro.googlegroups.com>
Hi all,

I'm writing a macro for with an embedded MACROLET like this:

(defmacro tst (&key arg)
  `(...
   (macrolet ((emb (emb-arg)
               `(... ,emb-arg ,@'(arg) ...))))


The point is that I want to access the outer argument from within the
inner macro's expansion...  the result after MACROEXPAND-1 should be:

call:  (tst :arg my-arg)

expansion:
(...
(macrolet ((emb (emb-arg)
            `(... ,emb-arg my-arg ...))))

By trial and error I found that isolating the outer argument ARG
inside a '() did what I wanted, so then I spliced with ,@.  Is that
wacky or WHAT??

Is there a better way?  (Again, SBCL...)

Thanks!

From: ··················@gmail.com
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <910b91e3-aa51-47a2-9298-5019bebe5a36@d23g2000yqc.googlegroups.com>
On Dec 2, 2:16 pm, fortunatus <··············@excite.com> wrote:
> Hi all,
>
> I'm writing a macro for with an embedded MACROLET like this:
>
> (defmacro tst (&key arg)
>   `(...
>    (macrolet ((emb (emb-arg)
>                `(... ,emb-arg ,@'(arg) ...))))
>
> The point is that I want to access the outer argument from within the
> inner macro's expansion...  the result after MACROEXPAND-1 should be:
>
> call:  (tst :arg my-arg)
>
> expansion:
> (...
> (macrolet ((emb (emb-arg)
>             `(... ,emb-arg my-arg ...))))
>
> By trial and error I found that isolating the outer argument ARG
> inside a '() did what I wanted, so then I spliced with ,@.  Is that
> wacky or WHAT??
>
> Is there a better way?  (Again, SBCL...)
>
> Thanks!

one , cancels out one ` ... when I'm doing macros embedded in macros i
generally prefer to keep myself straight by directly passing the
arguments with a 'let'.
ex:
(defmacro foo (symbol &key arg1)
 (do some stuff ..)
    `(defmacro ,(gensym symbol) (lambda-list-here) ;;one backquote
        (let ((arg2 ,arg1))
           (do .. some more stuff)
            `(return-form here ,arg2 etc.) ;;two backquote
         ) ;;end let
     ;; end inner macro
 );; end outer macro

Remember that generally you don't care about performance (except for
the inner most part) of a macro,
So whatever makes it most clear for you (and others) is best. Don't be
stingy.
From: ··············@excite.com
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <b71a71e1-b514-471a-9c30-5fcb47f393f8@k36g2000pri.googlegroups.com>
On Dec 2, 9:15 pm, ··················@gmail.com wrote:
> one , cancels out one ` ... when I'm doing macros embedded in macros i
> generally prefer to keep myself straight by directly passing the
> arguments with a 'let'.
> ex:
> (defmacro foo (symbol &key arg1)
>  (do some stuff ..)
>     `(defmacro ,(gensym symbol) (lambda-list-here) ;;one backquote
>         (let ((arg2 ,arg1))
>            (do .. some more stuff)
>             `(return-form here ,arg2 etc.) ;;two backquote
>          ) ;;end let
>      ;; end inner macro
>  );; end outer macro


Also a better way - nice!
From: Kaz Kylheku
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <20081218063330.71@gmail.com>
On 2008-12-02, fortunatus <··············@excite.com> wrote:
> Hi all,
>
> I'm writing a macro for with an embedded MACROLET like this:
>
> (defmacro tst (&key arg)
>   `(...
>    (macrolet ((emb (emb-arg)
>                `(... ,emb-arg ,@'(arg) ...))))
>

Since the use of ARG is nested in two backquotes, you need two levels of
unquoting to interpolate it.

As it is, you have two problems. First there is only one unquote, which belongs
to the innermost backquote ...

> The point is that I want to access the outer argument from within the
> inner macro's expansion...  the result after MACROEXPAND-1 should be:

Well, you can start by actually accessing the argument. :)  That's the second
problem: your ,@(QUOTE (ARG)) splices in the literal list (ARG), which has
nothing to do with the parameter ARG. It's a lot like this:


  ;;; two unrelated uses of ARG:
  (defun func (arg)
    (list 'arg)) 

The splicing operator is barking up the wrong tree. Looks like you were trying
to do ,@(list arg) which is equivalent to ,arg.  Splicing won't resolve the
nesting problem, because a splice provides a different shape of unquoting, not
an extra level of unquoting.

> call:  (tst :arg my-arg)
>
> expansion:
> (...
> (macrolet ((emb (emb-arg)
>             `(... ,emb-arg my-arg ...))))


The following is a step toward the solution, but not quite right:

                `(... ,emb-arg ,,arg ...)

One problem remains: unquoting involves evaluation. Nesting two unquotes means
that two evaluations are done also: ,ARG is reduced to ARG's value such as
MY-ARG, but then what is left is ,MY-ARG which wants to evaluate the MY-ARG
variable.  What we need is just one evaluation: reducing ARG to its value
such as MY-ARG.

How do we get just one evaluation, given that we need two levels of unquoting,
and each unquoting level calls for evalaution?

The trick is to allow one unquoting round to evaluate, and then suppress
evaluation in the subsequent round using regular quote:

                `(... ,emb-arg ,',arg ...)

The ,' cancel each other out as far evaluation is concerned, but still
represent a level of unquoting.  That is to say, both ,ARG and ,',ARG have the
effect of evaluating ARG once and substituting its value.  But they process
ARG at different levels of backquote nesting.

> By trial and error I found that isolating the outer argument ARG
> inside a '() did what I wanted

Haha! If the '() really had done what you wanted, you wouldn't have had any
reason to make the next change:

> so then I spliced with ,@. 

And then if /that/ worked, you wouldn't have posted to the newsgroup.

Cheers... :)
From: fortunatus
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <4272e2cc-6c4f-46f2-b2a9-8c4afb4a7179@g17g2000prg.googlegroups.com>
> > By trial and error I found that isolating the outer argument ARG
> > inside a '() did what I wanted
> Haha! If the '() really had done what you wanted, you wouldn't have had any
> reason to make the next change:
> > so then I spliced with ,@.
> And then if /that/ worked, you wouldn't have posted to the newsgroup.
> Cheers... :)

My mistake!  What I am actually doing is:

(defmacro tst (&key arg)
  `(...
   (macrolet ((emb (emb-arg)
               `(... ,emb-arg ,@'(,arg) ...))))

Note the addtional comma.  What I'm doing with this ,@'(,ARG) thing is
exactly what you suggested: isolate the levels of , expansion from
each other.

I've tried the ,',ARG form you suggested and SBCL did not accept it -
giving an error such as "comma not inside back quote" - even though it
made sense to me...
From: fortunatus
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <70bef5aa-13b7-4660-b2fd-a09d7ad3592d@t26g2000prh.googlegroups.com>
> > By trial and error I found that isolating the outer argument ARG
> > inside a '() did what I wanted
> Haha! If the '() really had done what you wanted, you wouldn't have had any
> reason to make the next change:
> > so then I spliced with ,@.
> And then if /that/ worked, you wouldn't have posted to the newsgroup.
> Cheers... :)

My mistake!  My code snippet should be:

(defmacro tst (&key arg)
  `(...
   (macrolet ((emb (emb-arg)
               `(... ,emb-arg ,@'(,arg) ...))))

Notice the additional comma.  My expression ,@'(,ARG) is doing just
what you point out, isolating the levels of expansion.

I tried your suggestion of ,',ARG and wow! It's a better way!  Thanks!
From: budden
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <6afcfec6-9eed-4882-806c-201cdd699599@f3g2000yqf.googlegroups.com>
Its too late here... Time to go to bed. But I see two bacquotes here
and three commas:

> (defmacro tst (&key arg)
>   `(...
>    (macrolet ((emb (emb-arg)
>                `(... ,emb-arg ,@'(,arg) ...))))
>   `            `     ,        ,   ,
I tried this:
> (defmacro tst (&key arg) `(list (macrolet ((emb (emb-arg)  `(list ,emb-arg ,@'(,arg) 1))))))
In a three implementations: clisp (old), lispworks (4.4.6), sbcl
(1.0.22). None implementation issued a message.

Congratulations! This looks like a flaw in a bacquoting algorithm
itself. Implementors seemed to copy it from cltl2 and error spread
over lisps. Maybe I am very tired and not adequate at all, but I'm
sure it is not good to allow three commas for two backquotes. Where is
a kenny who said "lisp is finished"? No. Lisp is a beta still. Ha-ha-
ha!!!

BTW, correct definition of what you want is:
(defmacro tst (&key arg) `(list (macrolet ((emb (emb-arg)  `(list ,emb-
arg ,',arg 1))))))
> (macroexpand-1 '(tst :arg :it-is-arg))
(macroexpand-1 '(tst :arg foo))
(LIST (MACROLET ((EMB (EMB-ARG) `(LIST ,EMB-ARG FOO 1)))))

Maybe there are errors somewhere else in your code?
From: Kaz Kylheku
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <20081218112152.928@gmail.com>
On 2008-12-02, budden <········@gmail.com> wrote:
> Its too late here... Time to go to bed. But I see two bacquotes here
> and three commas:

There are three commas in total, but they are distributed into two
terms in the backquote:

 ,emb-arg   ;; 1
 ,@'(,arg)  ;; 2 3

Maybe it's past late where you are, and actually too early!

> I tried this:
>> (defmacro tst (&key arg) `(list (macrolet ((emb (emb-arg)  `(list ,emb-arg ,@'(,arg) 1))))))
> In a three implementations: clisp (old), lispworks (4.4.6), sbcl
> (1.0.22). None implementation issued a message.

Because that's correct code.
From: Kaz Kylheku
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <20081218111705.65@gmail.com>
On 2008-12-02, fortunatus <··············@excite.com> wrote:
>> > By trial and error I found that isolating the outer argument ARG
>> > inside a '() did what I wanted
>> Haha! If the '() really had done what you wanted, you wouldn't have had any
>> reason to make the next change:
>> > so then I spliced with ,@.
>> And then if /that/ worked, you wouldn't have posted to the newsgroup.
>> Cheers... :)
>
> My mistake!  My code snippet should be:
>
> (defmacro tst (&key arg)
>   `(...
>    (macrolet ((emb (emb-arg)
>                `(... ,emb-arg ,@'(,arg) ...))))
>
> Notice the additional comma.  My expression ,@'(,ARG) is doing just
> what you point out, isolating the levels of expansion.

That is right.

,@'(,ARG) is equivalent to ,',ARG
 ^ ^
 \ \ 
  \_ splice cancels out list encapsulation!
From: budden
Subject: Re: Macro Writing Question #2
Date: 
Message-ID: <d76fd29b-e0db-4f64-b8a5-4e832252cf38@q9g2000yqc.googlegroups.com>
I'm sorry!
> There are three commas in total, but they are distributed into two terms in the backquote

I was too tired and in a bad mood and didn't notice that ,emb-arg do
not affect ,@'(,arg) nesting level.

When I get to bed it came to my mind but it was too late to stand up
and correct the letter (it was already sent anyway). Do you know that
it is a catastrophic unemployement growth in Russia? Yesterday I had
one more unsuccessful interview. Expected unemployement growth is up
to 20%. Most of us are not so bound with loans as Western people, but
this is a huge number anyway. And it is not the worst. I seldom read
the news, but yesterday I did it. The worst is an evident war
preparation in an Ukraine and a Georgia.

Sorry again for making such a stupid error, you see there are some
excuses for that.