@mck, I see why you want to use eval now. But it's a very messy solution, and slow, as I mentioned in my answer to the previous question. The classic On Lisp says this about eval:
"Generally it is not a good idea to call eval at runtime, for two reasons:
It’s inefficient: eval is handed a raw list, and either has to compile it on the
spot, or evaluate it in an interpreter. Either way is slower than compiling
the code beforehand, and just calling it.
It’s less powerful, because the expression is evaluated with no lexical context.
Among other things, this means that you can’t refer to ordinary
variables visible outside the expression being evaluated.
Usually, calling eval explicitly is like buying something in an airport gift-shop.
Having waited till the last moment, you have to pay high prices for a limited
selection of second-rate goods."
In this case the simplest thing is just to:
(defmacro testing-loop (var)
(let ((g (gensym)))
`(let ((,g ,var))
(if (consp ,g)
(loop for x from 0 to 5 collect x)
(loop for x from 0 to 5 and y in ,g collect y)))))
I know you want to factor out the common loop for x from 0 to 5 (which isn't actually needed in the second branch anyways). But loop is itself a macro which is converted at compile time to efficient, low level code. So the call to loop has to be built at compile time, using values which are available at compile time. You can't just insert an (if) in there which is intended to be evaluated at run time.
If you really don't want to repeat loop for x from 0 to 5, you could do something like:
(let ((a '(loop for x from 0 to 5)))
`(if (consp ,var)
(,@a collect x)
(,@a and y in ,var collect y)))
That's just to give you the idea; if you really do this, make sure to gensym!
A good lesson to learn from this is: when you are writing macros, you need to keep clearly in mind what is happening at compile time and what is happening at run time. The macro you wrote with eval compiles the loop macro dynamically, every time it is run, based on the return value of consp. You really want to compile the 2 different loop macros once, and just select the correct one at run-time.
EVALthere.EVALalways evaluates the form in the null lexical environment. Frankly, I don't really understand why you have the eval there in the first place.evalwas suggested to mck in the answers to the previous question. @mck: if you're trying to learn about macros by trying to figure out use cases for them and then find solutions for those use cases, maybe you should read OnLisp and/or Let Over Lambda. They cover a lot of interesting ground - I recommend starting with OnLisp, though.evalevaluates in the null lexical environment; learned something new. However, if I don't putevalthere, the macro returns the list of the code. What am I doing wrong?