From: j.k.
Subject: yet another macro question / ACL exercise Chp. 10, ex. 3
Date: 
Message-ID: <1143017344.477918.176230@v46g2000cwv.googlegroups.com>
Graham's "ANSI Common Lisp" has the following exercise (chp. 10, ex.
3):

Define a macro that takes a number n followed by one or more
expressions, and returns the value of the nth expression (without
evaluating the others, and counting the first arg as 1 and not 0).

My first solution (well, actually, like the hundredth, but the first
that works with all 3 of my test cases below) is as follows:

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

I've seen many cautions against using eval, suggesting that it is
usually not necessary, inefficient, etc. Is there some way I can do
this without using eval (or if eval is necessary, simpler or otherwise
better solutions)?

The solution should be able to handle all of the following, as my
solution does:

CL-USER> (let ((x 2))
  (nth-expr x (/ 1 0) (+ 1 2) (/ 1 0)))
3
CL-USER> (nth-expr 2 (/ 1 0) (+ 1 2) (/ 1 0))
3
CL-USER> (nth-expr (+ 1 1) (/ 1 0) (+ 1 2) (/ 1 0))
3

Any feedback would be appreciated.

Thanks,

j.k.

From: David Sletten
Subject: Re: yet another macro question / ACL exercise Chp. 10, ex. 3
Date: 
Message-ID: <BI8Uf.7734$WK1.4055@tornado.socal.rr.com>
j.k. wrote:

> Graham's "ANSI Common Lisp" has the following exercise (chp. 10, ex.
> 3):
> 
> Define a macro that takes a number n followed by one or more
> expressions, and returns the value of the nth expression (without
> evaluating the others, and counting the first arg as 1 and not 0).
> 
> My first solution (well, actually, like the hundredth, but the first
> that works with all 3 of my test cases below) is as follows:
> 
> (defmacro nth-expr (n &body exprs)
>   `(eval (nth (1- ,n) ',exprs)))
> 
> I've seen many cautions against using eval, suggesting that it is
> usually not necessary, inefficient, etc. Is there some way I can do
> this without using eval (or if eval is necessary, simpler or otherwise
> better solutions)?
> 
> The solution should be able to handle all of the following, as my
> solution does:
> 
> CL-USER> (let ((x 2))
>   (nth-expr x (/ 1 0) (+ 1 2) (/ 1 0)))
> 3
> CL-USER> (nth-expr 2 (/ 1 0) (+ 1 2) (/ 1 0))
> 3
> CL-USER> (nth-expr (+ 1 1) (/ 1 0) (+ 1 2) (/ 1 0))
> 3
> 
> Any feedback would be appreciated.
> 
> Thanks,
> 
> j.k.
> 

If you want to conditionally execute an expression, then use a 
conditional form. Here's one way:
(defmacro nth-expr (n &body body)
   `(case ,n ,@(loop for i from 1
                     for case in body
                     collect (list i case))))

CL-USER(179): (macroexpand-1 '(nth-expr (+ 1 1) (/ 1 0) (+ 1 2) (/ 1 0)))
(CASE (+ 1 1) (1 (/ 1 0)) (2 (+ 1 2)) (3 (/ 1 0)))

No EVAL necessary.

Aloha,
David Sletten
From: Lars Brinkhoff
Subject: Re: yet another macro question / ACL exercise Chp. 10, ex. 3
Date: 
Message-ID: <85y7z2vnt9.fsf@junk.nocrew.org>
"j.k." <·········@gmail.com> writes:
> Define a macro that takes a number n followed by one or more
> expressions, and returns the value of the nth expression (without
> evaluating the others, and counting the first arg as 1 and not 0).
>
> (defmacro nth-expr (n &body exprs)
>   `(eval (nth (1- ,n) ',exprs)))

(defmacro nth-expr (n &rest exprs)
  (nth (1- n) exprs))
From: j.k.
Subject: Re: yet another macro question / ACL exercise Chp. 10, ex. 3
Date: 
Message-ID: <1143048411.210775.250950@j33g2000cwa.googlegroups.com>
Lars Brinkhoff wrote:
> "j.k." <·········@gmail.com> writes:
> > Define a macro that takes a number n followed by one or more
> > expressions, and returns the value of the nth expression (without
> > evaluating the others, and counting the first arg as 1 and not 0).
> >
> > (defmacro nth-expr (n &body exprs)
> >   `(eval (nth (1- ,n) ',exprs)))
>
> (defmacro nth-expr (n &rest exprs)
>   (nth (1- n) exprs))

I tried this solution first, but it only works if 'n' is a literal
number.

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

Works fine. But

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

fails complaining that "X is not a number".
From: Pascal Bourguignon
Subject: Re: yet another macro question / ACL exercise Chp. 10, ex. 3
Date: 
Message-ID: <87odzyzh8z.fsf@thalassa.informatimago.com>
"j.k." <·········@gmail.com> writes:
> (defmacro nth-expr (n &body exprs)
>   `(eval (nth (1- ,n) ',exprs)))
>
> The solution should be able to handle all of the following, as my
> solution does:
>
> CL-USER> (let ((x 2))
>   (nth-expr x (/ 1 0) (+ 1 2) (/ 1 0)))
> 3
> CL-USER> (nth-expr 2 (/ 1 0) (+ 1 2) (/ 1 0))
> 3
> CL-USER> (nth-expr (+ 1 1) (/ 1 0) (+ 1 2) (/ 1 0))
> 3
>
> Any feedback would be appreciated.

Check David's message for a version that can handle this:

(let ((n 2) (x 3))  (nth-expr 0 (+ x 1) 0))

That's the reason why EVAL is not too useful.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Wanna go outside.
Oh, no! Help! I got outside!
Let me back inside!