Macros Clojure中常见宏错误的解决方法

Macros Clojure中常见宏错误的解决方法,macros,clojure,Macros,Clojure,基本上,我对宏还是比较陌生的,我正在努力研究如何用Clojure编写宏。问题是我不断地遇到异常错误,很难弄清楚该从哪里继续。所以我真正想知道的是,我是否可以得到调试Clojure宏的方法(或启发式方法)列表 以我正在处理的当前问题为例,我有以下模型: {:users [:name :email :registered-on] :post [:title :author]} 我想把它转换成以下形式: (do (def new-form-users (cashew.core/new-form "

基本上,我对宏还是比较陌生的,我正在努力研究如何用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,但我也遇到了同样的错误,我对如何解决这个问题几乎一无所知

他说:“当编译器看到一个宏时,它只是一个返回一些代码的函数,它运行该函数,并替换返回到程序中的代码。”提示我将宏编写为一个函数,它接受我拥有的值并输出我希望它们转换成的结果

因此,这项工作:

(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"))))
我不确定我在这里是否正确使用了宏,或者宏是否是解决此问题的正确策略。不过,如果您能提供一些关于编写宏时遇到异常时所做工作的想法,或者提供调试这些异常的良好技术,我们将不胜感激


编辑:米凯拉提醒我这不是一个好例子,但我的问题仍然存在。因此,重申一下,如果在clojure中编写宏时遇到异常情况,您会使用哪些技巧?

我个人不会为此使用宏-我建议的替代方法是:

  • 避免尝试在名称空间中生成新的符号名称-这可能会变得混乱和复杂
  • 而是创建一个名为“newforms”的数据结构,其中包含hashmap中的所有表单。您可以使用关键字或字符串作为键,我个人会使用“:users”这样的关键字,因为您已经在模型数据结构中使用了这种方法
  • 使用以模型为参数的函数生成“新表单”,并根据需要为模型中的每个表单调用
    (cashew.core/new-form…
  • 当您想要访问特定表单时,您可以执行
    (新表单:用户)
    或类似操作,从hashmap中读取相应的表单

那么一个嵌套的数据结构将包含我定义的所有函数?ie:(def newform:users{:new}:read}:post{:new}:read})?这与仅仅为这些生成的表单创建一个新名称空间有什么不同/它提供了什么优势?不过,我承认我用了一个可怕的例子,但它仍然不能回答我的问题。并不是说我太在意,这还是挺有用的!是的,我认为嵌套数据结构是最好的。我倾向于只对“我在源代码中手动定义的东西”使用名称空间。因此,我以编程方式创建/生成的任何东西通常都会放在数据结构中。这只是个人偏好(名称空间实际上是一种隐藏的映射!),但我发现这有助于避免名称空间中的混乱、维护问题和可能的冲突。你知道@mikera我真的开始欣赏这一评论,非常感谢你的想法。