2012-01-12 61 views
3

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感觉笨拙。有没有一种惯用的方式来做到这一点?我猜[email protected]是必要的,但我不能得到引用的权利。非常感谢。

+1

我不是特别擅长clojure,但它对我来说看起来很好! – 2012-01-12 22:02:03

回答

3

在这种情况下,你对使用apply的直觉很好。当你有一个引用的表格`,然后unqote所有这些可以帮助考虑将未引用的内容移动到最小的部分或列表中。这避免了使用代码来生成可以简单写入的表单。

user=> (defmacro deffoo [name & opt] `(def ~name [~(str name) [email protected]]))  
#'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) [email protected])))  
#'user/deffoo 
user=> (macroexpand '(deffoo "bar" 1 2 3))         
(def "bar" (user/mk-foo "bar" 1 2 3)) 

在第二种情况下,我们移动在一个水平~,让呼叫MK-FOO留报价,只是所享有建立参数列表所需的参数(使用拼接 - 无引号,如你所怀疑的)

+0

感谢您的快速回答。不幸的是,我的现实生活中的'mk-foo'比发布的插图要复杂得多。这不是手动内联扩展它的选项。我必须接电话。 – fizzer 2012-01-12 22:52:36

+0

使用以前的编辑之一中的mk-foo重新启动了该示例。 – 2012-01-13 02:35:53

+0

这个工作方式,+1,但延迟调用'mk-foo'来运行时间。 – fizzer 2012-01-13 12:39:30