Common Lisp:如何使用条件拼接在宏中构建列表?
让我们假设:
(defmacro testing (&optional var)
`(list 'this 'is
,@(when (consp var) `('a 'list))))
当被调用时:
>(testing 2)
(THIS IS)
>(testing (list 1 2))
(THIS IS A LIST)
这就是我想要的。但是现在,当我传递一个列表参数时:
>(defparameter bla (list 1 2 3))
BLA
>(testing bla)
(THIS IS)
我想这是因为宏会检查 (consp bla)
其中 bla 是一个符号,而不是列表?我该如何防止这种情况?
谢谢
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你可以这样做:
所以
var
将在运行时(而不是编译时)进行评估。var
在宏的扩展中只出现一次,但如果出现多次,则必须使用 gensym。编辑:如果您不想输入
'(this is)
两次,请执行以下操作:不要使用
eval
,它很慢,而且完全没有必要。通过将var
替换到宏扩展中,它自然会在运行时被评估。如果您使用 eval,您将执行如下操作:每次执行时,它都会构建一个表示代码的列表,并在运行之前对其进行编译。 (希望这不是循环!)如果您只使用生成简单代码的宏(没有
eval
),它只会编译一次。You could do something like:
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:Don't use
eval
, it's slow, and completely unnecessary. By substitutingvar
into the macro expansion, it will naturally be evaluated at run-time. If you use eval, you will be doing something like this: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
、(list 1 2)
和bla
。据我所知,唯一的解决方案是使用
eval
。这个特定的例子可以改变如下:但是,我想,你会同意,它真的很难看。如果你想使用词法变量,它就不起作用。通常,有一些方法可以重新表述问题,这样就不需要这样的扭曲。
The problem here is that the expression
is evaluated at compile time, when you only have literal (unevaluated) values of arguments. In your case:
2
,(list 1 2)
, andbla
.The only solution to this, that I'm aware of, is to use
eval
. This particular example can be changed as follows: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.