From: ··············@gmail.com
Subject: Tricky macro
Date: 
Message-ID: <1160636960.907851.44950@b28g2000cwb.googlegroups.com>
Hello list,

it may be a silly question, but nevertheless: for reasons which are too
long to explain here, I need to write the macro magic-macro with the
following properties: after

(setf alist '(1 2 3))

the following call

(macroexpand-1 '(magic-macro alist 4 5 6))

should yield (1 2 3 4 5 6) - in a sense, I need to do _double_
expansion inside magic-macro, so naive

(defmacro magic-macro (first &rest)
  `(,first ,@rest))

would not work - it will yield (alist 4 5 6). Can someone please shed
some light on it - I'm completely stuck now?

Best regards,
Victor.

From: Ken Tilton
Subject: Re: Tricky macro
Date: 
Message-ID: <UkmXg.873$gn7.88@newsfe08.lga>
··············@gmail.com wrote:
> Hello list,
> 
> it may be a silly question, but nevertheless: for reasons which are too
> long to explain here, I need to write the macro magic-macro with the
> following properties: after
> 
> (setf alist '(1 2 3))
> 
> the following call
> 
> (macroexpand-1 '(magic-macro alist 4 5 6))
> 
> should yield (1 2 3 4 5 6) - in a sense, I need to do _double_
> expansion inside magic-macro, so naive
> 
> (defmacro magic-macro (first &rest)

of course you mean (first &rest rest)...

>   `(,first ,@rest))
> 
> would not work - it will yield (alist 4 5 6). Can someone please shed
> some light on it - I'm completely stuck now?

Try `(append ,first (list ,@rest))

Above you say "I need to do -double- expansion...". Wrong. A macro just 
looks at source code at compile-time (cue Duane with his 
Macro-expansion-time rant), and the crucial source is just the symbol 
'alist. Think about it. What if code at runtime has modified alist to be 
'(a b c). Hopefully you want the runtime value to emerge from 
(magic-macro alist 4 5 6), or we have bigger issues to discuss. How do 
you get Lisp to use the runtime value of the symbol alist? Write some 
code such as (append alist ...etc...). How can you macrofy that? See 
above. However....

    (defun magic-fun (first &rest rest) (append first rest))

    (magic-fun alist 4 5 6)

...works as well, so you do not want a macro at all. Unfortunately, you 
began this alleged question with "for reasons too long to explain, I 
need to...", so.... uh, for reasons too long to explain, we really 
cannot help you. Pascal is your fortunate exception and should be along 
shortly to do whatever you tell him to. :)

kt

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: ··············@gmail.com
Subject: Re: Tricky macro
Date: 
Message-ID: <1160716169.619002.321180@b28g2000cwb.googlegroups.com>
Hello Ken, and thanks for your clarifying answers.

Ken Tilton wrote:
> of course you mean (first &rest rest)...

yep - that was a typo

> Above you say "I need to do -double- expansion...". Wrong. A macro just

<some good explanations skipped>

> ...works as well, so you do not want a macro at all. Unfortunately, you
> began this alleged question with "for reasons too long to explain, I
> need to...", so.... uh, for reasons too long to explain, we really
> cannot help you. Pascal is your fortunate exception and should be along
> shortly to do whatever you tell him to. :)

When I was writing "for reasons too long to explain..." I was expecting
something like that :). Of course my lack of explanation was not due to
disrespect to the group - I've just tried to cut off the unnecessary
details, and it seems that I've failed.

So here is the question I originally had in mind:

Exercise 3 in chapter 10 of Paul Graham's "ANSI Common Lisp" reads:
Define a macro that takes a number n followed my one or more
expressions, and returns the value of the nth expression:

(let ((n 2))
 (nth-expr n (/ 1 0) (+ 1 2) (/ 1 0)))

=> 3

(as you may see, neither of (/ 1 0) was evaluated). I've read and
re-read Chapter 10 several times yesterday, and was still unable to
find an answer. Today, after re-reading your post and Chapter 10
(again), I come up with the following:

(defmacro nth-expr (n &rest rest)
  `(eval (nth (- ,n 1) ',rest)))

which seems to do the trick. However, I still have some questions:

1) Is the way suggested above correct - and/or is there better (more
LISPish) version?
2) While playing with macroexpand-1, I was suprised by the following:

(macroexpand-1 '(dotimes (i 5) nil))

=> (DO ((I 0 (1+ I))) ((>= I 5))  NIL)

but

(macroexpand-1 '(dotimes (i n) nil))

=> (DO ((#:G1147 N) (I 0 (1+ I))) ((>= I #:G1147))  NIL)

- how macroexpand-1 can tell the difference between n and 5?
3) Evaluation version of Allegro CL 8.0 prints # inplace of some
interesting parts of macroexpansion - how should I tell it to show
everything?

(macroexpand '(dotimes (i 5) nil))

=>
(BLOCK NIL
  (LET ((I 0))
    (TAGBODY
      #:|Tag1|
        (COND (# #))
        (TAGBODY NIL)
        (PSETQ I (1+ I))
        (GO #:|Tag1|))))

Thanks again for your time & expertise,
Victor.
From: Zach Beane
Subject: Re: Tricky macro
Date: 
Message-ID: <m3odsgjz3t.fsf@unnamed.xach.com>
···············@gmail.com" <··············@gmail.com> writes:

> 
> Exercise 3 in chapter 10 of Paul Graham's "ANSI Common Lisp" reads:
> Define a macro that takes a number n followed my one or more
> expressions, and returns the value of the nth expression:
> 
> (let ((n 2))
>  (nth-expr n (/ 1 0) (+ 1 2) (/ 1 0)))
> 
> => 3
[snip]
>  I come up with the following:
> 
> (defmacro nth-expr (n &rest rest)
>   `(eval (nth (- ,n 1) ',rest)))
> 
> which seems to do the trick. However, I still have some questions:
> 
> 1) Is the way suggested above correct - and/or is there better (more
> LISPish) version?

This is not a very good approach. There are a lot of other, nicer
possibilities; see

   http://groups.google.com/groups/search?q=nth-expr

Zach
From: Pascal Bourguignon
Subject: Re: Tricky macro
Date: 
Message-ID: <8764eobvae.fsf@thalassa.informatimago.com>
···············@gmail.com" <··············@gmail.com> writes:

> 2) While playing with macroexpand-1, I was suprised by the following:
>
> (macroexpand-1 '(dotimes (i 5) nil))
>
> => (DO ((I 0 (1+ I))) ((>= I 5))  NIL)
>
> but
>
> (macroexpand-1 '(dotimes (i n) nil))
>
> => (DO ((#:G1147 N) (I 0 (1+ I))) ((>= I #:G1147))  NIL)
>
> - how macroexpand-1 can tell the difference between n and 5?

Using CONSTANTP.

     
> 3) Evaluation version of Allegro CL 8.0 prints # inplace of some
> interesting parts of macroexpansion - how should I tell it to show
> everything?

cf *print-length* *print-depth* *print-level* *print-lines*
There may also be some implementation dependent variables.

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

Nobody can fix the economy.  Nobody can be trusted with their finger
on the button.  Nobody's perfect.  VOTE FOR NOBODY.
From: Thomas A. Russ
Subject: Re: Tricky macro
Date: 
Message-ID: <ymiwt74xnsm.fsf@sevak.isi.edu>
Pascal Bourguignon <···@informatimago.com> writes:

> ···············@gmail.com" <··············@gmail.com> writes:
> 
> > 2) While playing with macroexpand-1, I was suprised by the following:
> >
> > (macroexpand-1 '(dotimes (i 5) nil))
> >
> > => (DO ((I 0 (1+ I))) ((>= I 5))  NIL)
> >
> > but
> >
> > (macroexpand-1 '(dotimes (i n) nil))
> >
> > => (DO ((#:G1147 N) (I 0 (1+ I))) ((>= I #:G1147))  NIL)
> >
> > - how macroexpand-1 can tell the difference between n and 5?
> 
> Using CONSTANTP.

And to be complete, it is actually the DOTIMES macro that can tell the
difference.  Macroexpand-1 just expands the macro that you give it.

> > 3) Evaluation version of Allegro CL 8.0 prints # inplace of some
> > interesting parts of macroexpansion - how should I tell it to show
> > everything?
> 
> cf *print-length* *print-depth* *print-level* *print-lines*
> There may also be some implementation dependent variables.

Allegro has some special "top level" values for these variables that
affect the printing in the read-eval-print loop.  They are

TPL:*PRINT-LENGTH* 
TPL:*PRINT-LEVEL* 

and need to be set separately for interactive use.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Ken Tilton
Subject: Re: Tricky macro
Date: 
Message-ID: <2ANXg.3885$lD3.1829@newsfe12.lga>
··············@gmail.com wrote:
> Hello Ken, and thanks for your clarifying answers.
> 
> Ken Tilton wrote:
> 
>>of course you mean (first &rest rest)...
> 
> 
> yep - that was a typo
> 
> 
>>Above you say "I need to do -double- expansion...". Wrong. A macro just
> 
> 
> <some good explanations skipped>
> 
>>...works as well, so you do not want a macro at all. Unfortunately, you
>>began this alleged question with "for reasons too long to explain, I
>>need to...", so.... uh, for reasons too long to explain, we really
>>cannot help you. Pascal is your fortunate exception and should be along
>>shortly to do whatever you tell him to. :)
> 
> 
> When I was writing "for reasons too long to explain..." I was expecting
> something like that :). Of course my lack of explanation was not due to
> disrespect to the group - I've just tried to cut off the unnecessary
> details, and it seems that I've failed.
> 
> So here is the question I originally had in mind:
> 
> Exercise 3 in chapter 10 of Paul Graham's "ANSI Common Lisp" reads:
> Define a macro that takes a number n followed my one or more
> expressions, and returns the value of the nth expression:
> 
> (let ((n 2))
>  (nth-expr n (/ 1 0) (+ 1 2) (/ 1 0)))
> 
> => 3
> 
> (as you may see, neither of (/ 1 0) was evaluated). I've read and
> re-read Chapter 10 several times yesterday, and was still unable to
> find an answer. Today, after re-reading your post and Chapter 10
> (again), I come up with the following:
> 
> (defmacro nth-expr (n &rest rest)
>   `(eval (nth (- ,n 1) ',rest)))
> 
> which seems to do the trick. However, I still have some questions:
> 
> 1) Is the way suggested above correct - and/or is there better (more
> LISPish) version?

I never use EVAL, and my guess is that doing so for this exercise keeps 
you from learning what PG had in mind for you. Zach has steered you to 
prior discussions of this exercise.

> 2) While playing with macroexpand-1, I was suprised by the following:
> 
> (macroexpand-1 '(dotimes (i 5) nil))
> 
> => (DO ((I 0 (1+ I))) ((>= I 5))  NIL)
> 
> but
> 
> (macroexpand-1 '(dotimes (i n) nil))
> 
> => (DO ((#:G1147 N) (I 0 (1+ I))) ((>= I #:G1147))  NIL)
> 
> - how macroexpand-1 can tell the difference between n and 5?

It does not, DOTIMES does that.

A macro is just another lisp function, so you can put debugging 
statements in it which run at macro exapnasion time.

(defmacro my-dotimes ((var times-form) &body body)
     (print (list :var var (type-of var)))
     ...etc for other args...
     `(dotimes (,var ,times-form) ,@body))

Untested. Anyway, if you then play around with various inputs to 
my-dotimes you will see what is going on.


> 3) Evaluation version of Allegro CL 8.0 prints # inplace of some
> interesting parts of macroexpansion - how should I tell it to show
> everything?

I /think/ that is some printer parameter you can play with something like:

(let ((*print-depth* 32))
    (print (macroexpand ....)))

Note that you need the print otherwise *print-depth* reverts to the 
lower value as the let form unwinds returning the value which only then 
gets printed by the REPL (at the lower print depth setting).

To avoid that just (setf *print-depth* 32) and then get longer print 
output until you setf it back.

Try (apropos "*PRINT") (or use the ACL apropos dialog on win32/linux) to 
explore other printer-controlling variables.


kt

> 
> (macroexpand '(dotimes (i 5) nil))
> 
> =>
> (BLOCK NIL
>   (LET ((I 0))
>     (TAGBODY
>       #:|Tag1|
>         (COND (# #))
>         (TAGBODY NIL)
>         (PSETQ I (1+ I))
>         (GO #:|Tag1|))))
> 
> Thanks again for your time & expertise,
> Victor.
> 

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Ken Tilton
Subject: Re: Tricky macro
Date: 
Message-ID: <PINXg.3886$lD3.3302@newsfe12.lga>
Ken Tilton wrote:
> 
> 
> ··············@gmail.com wrote:
> 
>> Hello Ken, and thanks for your clarifying answers.
>>
>> Ken Tilton wrote:
>>
>>> of course you mean (first &rest rest)...
>>
>>
>>
>> yep - that was a typo
>>
>>
>>> Above you say "I need to do -double- expansion...". Wrong. A macro just
>>
>>
>>
>> <some good explanations skipped>
>>
>>> ...works as well, so you do not want a macro at all. Unfortunately, you
>>> began this alleged question with "for reasons too long to explain, I
>>> need to...", so.... uh, for reasons too long to explain, we really
>>> cannot help you. Pascal is your fortunate exception and should be along
>>> shortly to do whatever you tell him to. :)
>>
>>
>>
>> When I was writing "for reasons too long to explain..." I was expecting
>> something like that :). Of course my lack of explanation was not due to
>> disrespect to the group - I've just tried to cut off the unnecessary
>> details, and it seems that I've failed.
>>
>> So here is the question I originally had in mind:
>>
>> Exercise 3 in chapter 10 of Paul Graham's "ANSI Common Lisp" reads:
>> Define a macro that takes a number n followed my one or more
>> expressions, and returns the value of the nth expression:
>>
>> (let ((n 2))
>>  (nth-expr n (/ 1 0) (+ 1 2) (/ 1 0)))
>>
>> => 3
>>
>> (as you may see, neither of (/ 1 0) was evaluated). I've read and
>> re-read Chapter 10 several times yesterday, and was still unable to
>> find an answer.

Those exercises are pretty diabolical, as in well-designed to really 
teach you a lot if you can ever sort them out. So don't feel bad or 
think you are missing something obvious, they are supposed to be brutal.

>> Today, after re-reading your post and Chapter 10
>> (again), I come up with the following:
>>
>> (defmacro nth-expr (n &rest rest)
>>   `(eval (nth (- ,n 1) ',rest)))
>>
>> which seems to do the trick. However, I still have some questions:
>>
>> 1) Is the way suggested above correct - and/or is there better (more
>> LISPish) version?
> 
> 
> I never use EVAL, and my guess is that doing so for this exercise keeps 
> you from learning what PG had in mind for you. Zach has steered you to 
> prior discussions of this exercise.
> 
>> 2) While playing with macroexpand-1, I was suprised by the following:
>>
>> (macroexpand-1 '(dotimes (i 5) nil))
>>
>> => (DO ((I 0 (1+ I))) ((>= I 5))  NIL)
>>
>> but
>>
>> (macroexpand-1 '(dotimes (i n) nil))
>>
>> => (DO ((#:G1147 N) (I 0 (1+ I))) ((>= I #:G1147))  NIL)
>>
>> - how macroexpand-1 can tell the difference between n and 5?
> 
> 
> It does not, DOTIMES does that.
> 
> A macro is just another lisp function, so you can put debugging 
> statements in it which run at macro exapnasion time.
> 
> (defmacro my-dotimes ((var times-form) &body body)
>     (print (list :var var (type-of var)))
>     ...etc for other args...
>     `(dotimes (,var ,times-form) ,@body))
> 
> Untested. Anyway, if you then play around with various inputs to 
> my-dotimes you will see what is going on.

And notice also that the print statements run at the time macroexpand 
(via your macro) produces the code the application would someday be 
running. This should start driving home the key macro trick: a macro is 
code that runs now and sees source to produce code that runs later and 
sees values. And when the source happens to be 5...

kt

> 
> 
>> 3) Evaluation version of Allegro CL 8.0 prints # inplace of some
>> interesting parts of macroexpansion - how should I tell it to show
>> everything?
> 
> 
> I /think/ that is some printer parameter you can play with something like:
> 
> (let ((*print-depth* 32))
>    (print (macroexpand ....)))
> 
> Note that you need the print otherwise *print-depth* reverts to the 
> lower value as the let form unwinds returning the value which only then 
> gets printed by the REPL (at the lower print depth setting).
> 
> To avoid that just (setf *print-depth* 32) and then get longer print 
> output until you setf it back.
> 
> Try (apropos "*PRINT") (or use the ACL apropos dialog on win32/linux) to 
> explore other printer-controlling variables.
> 
> 
> kt
> 
>>
>> (macroexpand '(dotimes (i 5) nil))
>>
>> =>
>> (BLOCK NIL
>>   (LET ((I 0))
>>     (TAGBODY
>>       #:|Tag1|
>>         (COND (# #))
>>         (TAGBODY NIL)
>>         (PSETQ I (1+ I))
>>         (GO #:|Tag1|))))
>>
>> Thanks again for your time & expertise,
>> Victor.
>>
> 

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Alan Crowe
Subject: Re: Tricky macro
Date: 
Message-ID: <86bqohct4u.fsf@cawtech.freeserve.co.uk>
··············@gmail.com writes:

> Hello list,
> 
> it may be a silly question, but nevertheless: for reasons which are too
> long to explain here, I need to write the macro magic-macro with the
> following properties: after
> 
> (setf alist '(1 2 3))
> 
> the following call
> 
> (macroexpand-1 '(magic-macro alist 4 5 6))
> 
> should yield (1 2 3 4 5 6) - in a sense, I need to do _double_
> expansion inside magic-macro, so naive
> 
> (defmacro magic-macro (first &rest)
>   `(,first ,@rest))
> 
> would not work - it will yield (alist 4 5 6). Can someone please shed
> some light on it - I'm completely stuck now?
> 
> Best regards,
> Victor.

Make your WHEN's explicit.

Set your problem in the context of compiling on one machine
and ftp-ing the executable to a different machine before
loading.

Which machine executes (setf alist '(1 2 3))

Note that (eval 4) => 4 so we cannot see whether an
evaluation is intended.

Is it

(macroexpand-1 '(magic-macro alist (+ 2 2) 5 6)) 
  => (1 2 3 4 5 6)

or

(macroexpand-1 '(magic-macro alist (+ 2 2) 5 6)) 
  => (1 2 3 (+ 2 2) 5 6)

Such uncertainties discourgage would be helpers.

Alan Crowe
Edinburgh
Scotland
From: ··············@gmail.com
Subject: Re: Tricky macro
Date: 
Message-ID: <1160755069.693742.178790@b28g2000cwb.googlegroups.com>
Alan, Ken, Pascal and Zach - thanks a lot for your comments.

It strange that I've never managed to use search and asked the same
basic question that reader's of Mr. Graham's book ask every other month
in this group... I could imagine how much patience is needed to answer
the same questions over and over again. Well, the lesson is learned.

Have a good day,
Victor.