编写用于生成函数/多重方法的宏
Writing macro for generating functions / multimethods
我目前正在尝试使用 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"))
一切看起来都很好,除了参数向量,它在扩展后是空的。
我错过了什么?
如果你想让隐含的arg
存在于你需要写的正文中:
(defmacro add-command [command-name command-impl]
`(defmethod command ~command-name [~'arg] ~@command-impl))
相反。照应宏(引入固定名称的宏,如 arg
此处)在 Clojure 中通常 unusual/frowned。
请注意,对您的示例进行宏扩展后,我得到了与您不同的(和预期的)结果:
(clojure.core/defmethod user/command "new-command" (quote [user/arg]) print "new-command")
我目前正在尝试使用 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"))
一切看起来都很好,除了参数向量,它在扩展后是空的。
我错过了什么?
如果你想让隐含的arg
存在于你需要写的正文中:
(defmacro add-command [command-name command-impl]
`(defmethod command ~command-name [~'arg] ~@command-impl))
相反。照应宏(引入固定名称的宏,如 arg
此处)在 Clojure 中通常 unusual/frowned。
请注意,对您的示例进行宏扩展后,我得到了与您不同的(和预期的)结果:
(clojure.core/defmethod user/command "new-command" (quote [user/arg]) print "new-command")