【问题标题】:Writing macro for generating functions / multimethods为生成函数/多方法编写宏
【发布时间】:2015-09-15 09:27:31
【问题描述】:

我目前正在尝试通过使用 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"))

一切看起来都不错,除了参数向量,它在展开后是空的。

我错过了什么?

【问题讨论】:

    标签: clojure macros


    【解决方案1】:

    如果您希望隐含的arg 存在于您需要编写的正文中:

    (defmacro add-command [command-name command-impl]
       `(defmethod command ~command-name [~'arg] ~@command-impl))
    

    相反。照应宏(此处引入固定名称的宏,如 arg)在 Clojure 中通常不常见/不受欢迎。

    请注意,对您的示例进行宏扩展后,我会得到与您的示例不同的(和预期的)结果:

    (clojure.core/defmethod user/command "new-command" (quote [user/arg]) print "new-command")
    

    【讨论】:

    • 我不认为以下是必要的:~'arg。您是否有理由不直接以反引号形式写arg?命名空间问题?
    • 好吧,测试表明我“不能使用限定名称作为参数”仅使用 arg。现在说得通了:-)
    • @coredump 是的,这是 Clojure 的宏观卫生方法:很难偶然引入名称。
    猜你喜欢
    • 2011-12-12
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多