基本上我对宏很新,我正在尝试研究如何在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"))))
我不确定我是否在这里正确使用宏,或者宏是否是解决此问题的正确策略。然而,在编写宏或遇到异常时你会做些什么的一些想法非常感谢用于调试它们的良好技术。
答案 0 :(得分:2)
就我个人而言,我不会使用宏 - 我建议的替代方案是:
(cashew.core/new-form ... )
(new-forms :users)
或类似操作,从哈希映射中读取相应的表单。