Hi,
I am a lisp newbie currently reading Grahams "Ansi Common Lisp".
I have some trouble solving exercise 10.3. The reader is supposed
to write a macro which takes a number n and some expressions and
returns the nth expression evaluated. All other expressions shoud not
be evaluated.
So far I got:
(defmacro nth-expr (n &rest args)
`(eval (nth (1- ,n) ',args)))
I doubt this is what Graham had in mind as it uses evil eval.
thanks in advance
regards,
cp
Christian Pohlmann <···········@yahoo.com> writes:
> Hi,
>
> I am a lisp newbie currently reading Grahams "Ansi Common Lisp".
> I have some trouble solving exercise 10.3. The reader is supposed
> to write a macro which takes a number n and some expressions and
> returns the nth expression evaluated. All other expressions shoud not
> be evaluated.
The _student_ is supposed to _write_. The (lisp) _reader_ only reads ;-)
> So far I got:
>
> (defmacro nth-expr (n &rest args)
> `(eval (nth (1- ,n) ',args)))
>
> I doubt this is what Graham had in mind as it uses evil eval.
Indeed.
When it says it returns the nth expression evaluated, it doesn't mean
the _macro_ will evaluatate the nth expression. It means the macro
will _return_ the nth expression to have it compiled-and-evaluated or
interpreted.
A macro is but a function that returns a s-expression instead of
returning a mere value.
Let's write a function that returns it's nth+1 argument (note, that in
lisp we usually counts from 0):
(defun f-nth-expr (n &rest args)
(nth n args))
(f-nth-expr 3 '(+ 1 2) '(- 3 4) '(* 5 6) '(/ 7 8))
--> (/ 7 8)
(f-nth-expr 1 '(+ 1 2) '(- 3 4) '(* 5 6) '(/ 7 8))
--> (- 3 4)
None of the s-expressions (+ 1 2), (- 3 4), (* 5 6), (/ 7 8) are
evaluated. One of them is selected and returned.
Now, the macro doesn't need to do more:
(defmacro nth-expr (n &rest args) (apply (function f-nth-expr) n args))
(macroexpand '(nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
--> (* 5 6)
Of course, since f-nth-expr does nothing more than nth, we could write
instead:
(nth 3 '((+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
--> (/ 7 8)
and simplify the macro:
(defmacro nth-expr (n &rest args) (nth n args))
(macroexpand '(nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
--> (* 5 6)
(nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))
--> 30
The macro returns the s-expression (* 5 6), and the interpreter evaluates
this expression instead of (nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))
--
__Pascal Bourguignon__ http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
Pascal Bourguignon <···@informatimago.com> writes:
> Christian Pohlmann <···········@yahoo.com> writes:
>
>> I am a lisp newbie currently reading Grahams "Ansi Common Lisp".
>> I have some trouble solving exercise 10.3. The reader is supposed
>> to write a macro which takes a number n and some expressions and
>> returns the nth expression evaluated. All other expressions shoud not
>> be evaluated.
[snip]
> Of course, since f-nth-expr does nothing more than nth, we could write
> instead:
> (nth 3 '((+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
> --> (/ 7 8)
> and simplify the macro:
> (defmacro nth-expr (n &rest args) (nth n args))
When I read Ansi Common Lisp (to learn CL, not for school), I did all
of the problems in the book, and I just went back to look at my answer
to 10.3. Clearly, I hadn't solved it the way it was intended:
(defmacro nth-expr (n &rest exps)
`(case ,n
,@(let ((i -1))
(mapcar #'(lambda (exp)
`(,(incf i) ,exp))
exps))))
I suppose the compiler would have optimized this for me. Oh well, I'm
still a newbie, but at least now I can say that I would have come up
with the better answer that Pascal provided.
> (defmacro nth-expr (n &rest args) (nth n args))
>
> (macroexpand '(nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
> --> (* 5 6)
But this fails:
(macroexpand '(nth-expr n (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
>
> (nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))
> --> 30
>
> The macro returns the s-expression (* 5 6), and the interpreter evaluates
> this expression instead of (nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))
If you already know that you want (* 5 6), there's little point
to write (nth-expr ....).
I believe the OP is supposed to write a macro that expands
to CASE or COND or IF or whatever form that select a right
expression at runtime.
····@gol.com (Takehiko Abe) writes:
>> (defmacro nth-expr (n &rest args) (nth n args))
>>
>> (macroexpand '(nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
>> --> (* 5 6)
>
> But this fails:
>
> (macroexpand '(nth-expr n (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
Of course. The OP did not specify that the macro take a symbol or an
expression. He specified it takes a number.
(nth-expr (mod n 4) (+ 1 2) (- 3 4) (* 5 6) (/ 7 8)))
will fail too.
>> (nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))
>> --> 30
>>
>> The macro returns the s-expression (* 5 6), and the interpreter evaluates
>> this expression instead of (nth-expr 2 (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))
>
> If you already know that you want (* 5 6), there's little point
> to write (nth-expr ....).
>
> I believe the OP is supposed to write a macro that expands
> to CASE or COND or IF or whatever form that select a right
> expression at runtime.
Ok.
(defmacro nth-expr (n &body expressions)
`(case ,n
,@(let ((i -1))
(mapcar (lambda (expr) `((,(incf i)) ,expr)) expressions))
(otherwise (error "nth-expr: out of bounds."))))
(dotimes (n 4)
(print (nth-expr n (+ 1 2) (- 3 4) (* 5 6) (/ 7 8))))
3
-1
30
7/8
--> NIL
--
__Pascal Bourguignon__ http://www.informatimago.com/
The world will now reboot. don't bother saving your artefacts.
> Of course. The OP did not specify that the macro take a symbol or an
> expression. He specified it takes a number.
>
He said it takes a number n and and did not say that the macro must
take a form that evaluates to an integer. But it is rather obvious
that the latter is what is required.