Common Lisp: How to build a list in a macro with conditional splicing?

只愿长相守 提交于 2019-12-14 04:18:59

问题


Let's assume:

(defmacro testing (&optional var)
    `(list 'this 'is  
       ,@(when (consp var) `('a 'list))))

when called:

>(testing 2)
(THIS IS)

>(testing (list 1 2))
(THIS IS A LIST)

which is what I wanted. But now, when I pass a parameter that is a list:

>(defparameter bla (list 1 2 3))
BLA
>(testing bla)
(THIS IS)

which I suppose is because the macro would check (consp bla) where bla is a symbol, instead of the list? How do I prevent this?

Thanks


回答1:


You could do something like:

(defmacro testing (&optional var)
   `(if (consp ,var)
        '(this is a list)
        '(this is)))

So var will be evaluated at run time (not compile time). var only appears one time in the expansion of the macro, but if it appeared more than once, you would have to use a gensym.

EDIT: If you don't want to type '(this is) twice, do this:

(defmacro testing (&optional var)
  `(append '(this is) (when (consp ,var) '(a list))))

Don't use eval, it's slow, and completely unnecessary. By substituting var into the macro expansion, it will naturally be evaluated at run-time. If you use eval, you will be doing something like this:

(eval (append '(list 'this 'is) (when (consp 'bla) '('a 'list))))

Every time that executes, it will build up a list representing the code and compile it before running it. (Hopefully this isn't in a loop!) If you just use a macro which generates straightforward code (without eval), it will compile only once.




回答2:


The problem here is that the expression

,@(when (consp var) `('a 'list))))

is evaluated at compile time, when you only have literal (unevaluated) values of arguments. In your case: 2, (list 1 2), and bla.

The only solution to this, that I'm aware of, is to use eval. This particular example can be changed as follows:

(defmacro testing (&optional var)
  `(eval (append '(list 'this 'is)  
                 (when (consp ',var)
                   '('a 'list))))

But, I think, you'll agree, that its really ugly. And it won't work if you want to use lexical variables. Usually, there are ways to reformulate the problem, so that such perversions aren't needed.



来源:https://stackoverflow.com/questions/9214673/common-lisp-how-to-build-a-list-in-a-macro-with-conditional-splicing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!