Clojure宏noob在这里。我有一个带有一些可选参数的函数,例如
(defn mk-foo [name & opt]
(vec (list* name opt)))
给出这个:
user> (mk-foo "bar" 1 2 3)
["bar" 1 2 3]
我正在尝试编写一个宏,它接受相同的可选参数,并将它们透明地传递给mk-foo
的调用。到目前为止,我有这个:
(defmacro deffoo [name & opt]
`(def ~name ~(apply mk-foo (str name) opt)))
具有所需的效果:
user> (macroexpand '(deffoo bar 1 2 3))
(def bar ["bar" 1 2 3])
使用apply
来压缩列表opt
感觉很笨拙。这是否有惯用的方法?我猜测需要~@
,但我无法正确引用。非常感谢。
答案 0 :(得分:3)
在这种情况下,你对使用申请的直觉很好。当你有一个引用的形式`然后取消所有这些时,它可以帮助考虑将未引用向下移动到最小的部分或列表。这避免了使用代码生成可以简单编写的表单。
user=> (defmacro deffoo [name & opt] `(def ~name [~(str name) ~@opt]))
#'user/deffoo
user=> (macroexpand '(deffoo "bar" 1 2 3))
(def "bar" ["bar" 1 2 3])
这里是对mk-foo的调用:
(defmacro deffoo [name & opt] `(def ~name (mk-foo ~(str name) ~@opt)))
#'user/deffoo
user=> (macroexpand '(deffoo "bar" 1 2 3))
(def "bar" (user/mk-foo "bar" 1 2 3))
在第二种情况下,我们将~
移动到一个级别,并让对mk-foo的调用保持引用,并且仅取消引用构建参数列表所需的args(使用拼接 - 取消引用,如您所怀疑的)