如何将可选的宏args传递给函数

时间:2012-01-12 21:50:29

标签: clojure

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感觉很笨拙。这是否有惯用的方法?我猜测需要~@,但我无法正确引用。非常感谢。

1 个答案:

答案 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(使用拼接 - 取消引用,如您所怀疑的)