我当前正试图通过使用Clojure宏来提供DSL。我的库的用户必须能够使用该DSL扩展它。该库为开箱即用的某些命令提供了一种多方法和一些使用defmethod的基线实现。让我们说,我们有一个多方法:
(defmulti command command-name)
以及一些由库提供的命令:
(defmethod command "say-hello" [arg] (println "hello" arg))
(defmethod command "say-bye" [arg] (println "bye" arg))
我们的想法是编写一个生成这些defmethods的宏,因此用户不需要自己编写defmethods,而是使用我的DSL。关于这一点,我写了以下宏:
(defmacro add-command [command-name command-impl]
`(defmethod command ~command-name '[arg] ~@command-impl))
我得到的是,每当我使用我的宏时,(add-command "new-command" (print "new-command"))
以下异常" java.lang.IllegalArgumentException :参数声明应该是一个向量"
如果我扩展宏:
(clojure.core/defmethod com.foo/on-error "new-command" [] (println "starting"))
一切看起来都不错,但参数向量除外,它在展开后为空。
我错过了什么?
答案 0 :(得分:3)
如果您希望隐含的arg
存在于您需要编写的正文中:
(defmacro add-command [command-name command-impl]
`(defmethod command ~command-name [~'arg] ~@command-impl))
代替。在Clojure中,回指宏(在这里引用固定名称如arg
的宏)通常是不寻常/不受欢迎的。
请注意,宏扩展您的示例我会得到您的不同(和预期)结果:
(clojure.core/defmethod user/command "new-command" (quote [user/arg]) print "new-command")