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.
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))
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".
"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!