Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>@mck, I see why you want to use <code>eval</code> now. But it's a very messy solution, and slow, as I mentioned in my answer to the previous question. The classic <em>On Lisp</em> says this about <code>eval</code>:</p> <p>"Generally it is not a good idea to call eval at runtime, for two reasons:</p> <ol> <li><p>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.</p></li> <li><p>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.</p></li> </ol> <p>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."</p> <p>In this case the simplest thing is just to:</p> <pre><code>(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))))) </code></pre> <p>I know you want to factor out the common <code>loop for x from 0 to 5</code> (which isn't actually needed in the second branch anyways). But <code>loop</code> is itself a macro which is converted <em>at compile time</em> to efficient, low level code. So the call to <code>loop</code> has to be built <em>at compile time</em>, using values which are available at compile time. You can't just insert an <code>(if)</code> in there which is intended to be evaluated at run time.</p> <p>If you really don't want to repeat <code>loop for x from 0 to 5</code>, you could do something like:</p> <pre><code>(let ((a '(loop for x from 0 to 5))) `(if (consp ,var) (,@a collect x) (,@a and y in ,var collect y))) </code></pre> <p>That's just to give you the idea; if you really do this, make sure to <code>gensym</code>!</p> <p>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 <code>eval</code> compiles the <code>loop</code> macro dynamically, <em>every time it is run</em>, based on the return value of <code>consp</code>. You really want to compile the 2 different <code>loop</code> macros once, and just select the correct one at run-time.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload