如果我想定义一个接受未知数量的args的函数,我可以轻松地做这样的事情:
(defn foo
[& args]
args)
返回类型为clojure.lang.ArraySeq
的值,其中包含函数中给出的值。
在宏中,使用~@
是非引号拼接,这使得给出的论点变得平坦:
(defmacro foo
[bar & baz]
`(println ~@baz))
如果我像这样使用宏:
(foo "foo" 1 2 3 4)
它将打印出1 2 3 4
。但是,我想让args不讨好。执行~baz
(没有@
)会给我一个例外。知道怎么做吗?
答案 0 :(得分:3)
如果您使用macroexpand-1
~baz
版本,问题的原因就会变得明显:
(macroexpand-1 '(foo "foo" 1 2 3 4)) ; NB. using ~baz in foo's body
;= (println (1 2 3 4))
; ^
所以我们在这里尝试将1
作为一个函数来调用。 (注意:此调用发生并且在运行时抛出异常。)
解决此问题的正确方法取决于您希望实现的目标。例如,您可以将其余的arg倒入矢量并打印出:
(defmacro foo [bar & baz]
`(println ~(vec baz)))
答案 1 :(得分:2)
评论MichałMarczyk的答案......
您还可以通过将宏转换为函数来查看正在发生的事情:
(defn foo [bar & baz]
`(println ~@baz))
=> (foo "foo" 1 2 3 4)
(clojure.core/println (1 2 3 4))
语法引用,取消引用和取消引用拼接仍然有效。啊哈!宏与调用它们的函数不同,而不是它们的作用。
答案 2 :(得分:1)
你可以随时
(defmacro foo
[bar & baz]
`(println (list ~@baz)))
构建seq或
(defmacro foo
[bar & baz]
`(println [~@baz]))
构造一个向量。