不引用[& args]在宏观上

时间:2014-03-13 08:02:58

标签: macros clojure

如果我想定义一个接受未知数量的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(没有@)会给我一个例外。知道怎么做吗?

3 个答案:

答案 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]))

构造一个向量。