2016-09-27 33 views
1

我试图编写一个宏来比较多个表达式的运行时间,并将其运行到墙上。我的问题可以浓缩为下面的代码:使用可变参数宏作为列表

(defmacro test-m [& exprs] 
    `(map #(.toString %) ~exprs)) 

如果我把这种喜欢(test-m 1 2 3),我希望它可以沿着线生产代码:

(map #(.toString %) [1 2 3]) 

这是完全有效的。但不幸的是,这实际上导致一个错误:

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn helpers.general-helpers/eval663 (NO_SOURCE_FILE:76)

的唯一途径,我可以看到这个可能发生的事情是,如果& exprs导致(1 2 3),那么这将尝试调用1的功能,这显然是错误的。

如何映射宏中的可变参数列表?

回答

3

我在写这个问题的时候想到了它,所以我想我会发布一个答案,以防其他人在未来陷入困境。

参数列表需要首先强制进入列表表达式,否则它将被评估为表单。这是可以做到这样的:

(defmacro test-m [& exprs] 
    `(map #(.toString %) (list [email protected])) 

注意exprs通过@扩大,并给予list。 (感谢@amalloy纠正)。

明显是回顾,但它让我暂时停留了一段时间。希望这有助于某人。

+0

你可能不想引用它,而是写'(list〜@ exprs)'或'〜(vec exprs)'。 – amalloy

+0

@amalloy最后有什么不同?引用它似乎更直接。我并不想争辩;我很好奇。 – Carcigenicate

+0

用x y z变量而不是1 2 3个常量尝试。 – amalloy