【发布时间】:2011-05-08 21:23:08
【问题描述】:
基本上我对宏比较陌生,我正在尝试研究如何在 Clojure 中编写宏。问题是我不断收到异常错误,很难弄清楚从哪里继续。所以我真正想知道的是,我是否可以获得用于调试 Clojure 宏的任一方法(或启发式)的列表。
以我正在处理的当前问题为例,我有这个模型:
{:users [:name :email :registered-on]
:post [:title :author]}
我想把它转换成形式:
(do (def new-form-users (cashew.core/new-form "/users/new" "Create a new Users"
["name" "email" "registered-on"] ("Name" "Email" "Registered-on")))
(def new-form-post (cashew.core/new-form "/post/new" "Create a new Post"
["title" "author"] ("Title" "Author"))))
我为此编写了这个宏:
(defmacro gen-create-forms [model]
`(do
~@(for [[entity-kw values] model]
(let [entity-sym (-> entity-kw name capitalize)
fields (vec (map name values))]
`(def ~(symbol (str "new-form-" (name entity-kw))) (new-form ~(str "/" (name entity-kw) "/new") ~(str "Create a new " entity-sym) ~fields ~(map capitalize fields)))))))
但是,当我运行宏时,我得到:
java.lang.String cannot be cast to clojure.lang.IFn
[Thrown class java.lang.ClassCastException]
我试过调用macroexpand-1,但我得到了同样的错误,让我对如何解决它一无所知。
This tutorial provided by John Lawrence Aspden 他说“当编译器看到一个宏,它只是一个返回一些代码的函数时,它会运行该函数,并替换返回到程序中的代码。”提示我将宏编写为一个函数,该函数接受我拥有的值并输出我希望它们转换成的结果。
这样就可以了:
(defn gen-create-forms [model]
`(do
~@(for [[entity-kw values] model]
(let [entity-sym (-> entity-kw name capitalize)
fields (vec (map name values))]
`(def ~(symbol (str "new-form-" (name entity-kw))) (new-form ~(str "/" (name entity-kw) "/new") ~(str "Create a new " entity-sym) ~fields ~(map capitalize fields)))))))
(gen-create-forms {:users [:name :email :registered-on]
:post [:title :author]})
(do (def new-form-users (cashew.core/new-form "/users/new" "Create a new Users" ["name" "email" "registered-on"] ("Name" "Email" "Registered-on"))) (def new-form-post (cashew.core/new-form "/post/new" "Create a new Post" ["title" "author"] ("Title" "Author"))))
我不确定我在这里是否正确使用了宏,或者宏是否是解决此问题的正确策略。 但是,关于在编写宏或遇到异常时如何处理的一些想法调试它们的好技术将不胜感激。
编辑:mikera 已经引起我的注意,这不是一个很好的例子,但是我的问题仍然存在。因此,重申一下如果在 clojure 中编写宏,当遇到异常时您会使用哪些技术?
【问题讨论】: