Macros 在宏上取消引号[&;args]
如果我想定义一个接受未知数量参数的函数,我可以很容易地执行以下操作:Macros 在宏上取消引号[&;args],macros,clojure,Macros,Clojure,如果我想定义一个接受未知数量参数的函数,我可以很容易地执行以下操作: (defn foo [& args] args) (foo "foo" 1 2 3 4) 它返回类型为clojure.lang.ArraySeq的值,其中包含函数中给定的值 在宏中,使用~@是取消报价拼接,这会展平给定的参数: (defmacro foo [bar & baz] `(println ~@baz)) 如果我像这样使用宏: (defn foo [& args]
(defn foo
[& args]
args)
(foo "foo" 1 2 3 4)
它返回类型为clojure.lang.ArraySeq
的值,其中包含函数中给定的值
在宏中,使用~@
是取消报价拼接,这会展平给定的参数:
(defmacro foo
[bar & baz]
`(println ~@baz))
如果我像这样使用宏:
(defn foo
[& args]
args)
(foo "foo" 1 2 3 4)
它将打印出1234
。但是,我想让ARG们放松。做~baz
(没有@
)会给我一个例外。你知道怎么做吗?你总能做到
(defmacro foo
[bar & baz]
`(println (list ~@baz)))
构造一个seq或
(defmacro foo
[bar & baz]
`(println [~@baz]))
构造一个向量 如果您使用
macroexpand-1
使用~baz
的版本,则问题的原因显而易见:
(macroexpand-1 '(foo "foo" 1 2 3 4)) ; NB. using ~baz in foo's body
;= (println (1 2 3 4))
; ^
因此,这里我们试图将1
作为函数调用。(注意:此调用发生,并且在运行时引发异常。)
解决这一问题的正确方法取决于您想要实现的目标。例如,您可以将剩余参数倒入向量并打印:
(defmacro foo [bar & baz]
`(println ~(vec baz)))
对MichałMarczyk回答的评论 通过将宏转换为函数,您还可以看到发生了什么:
(defn foo [bar & baz]
`(println ~@baz))
=> (foo "foo" 1 2 3 4)
(clojure.core/println (1 2 3 4))
语法引用、取消引用和取消引用拼接仍然有效。啊哈!宏与函数的不同之处在于调用它们的方式,而不是它们的作用 感谢您提及
macroexpand-1