【问题标题】:How to generate arguments of a Clojure macro dynamically?如何动态生成 Clojure 宏的参数?
【发布时间】:2011-07-24 21:02:08
【问题描述】:

我目前正在开发一个小型 CMS,使用出色的 Enlive 作为模板引擎。 Enlive 有一个名为 at 的宏,它接受一个指定 HTML sn-p 的节点(映射)和任意数量的元组,每个元组由一个选择器(一个向量)和一个转换(一个闭包)组成。

(at a-node
  [:a :selector] a-transformation
  [:another :selector] another-transformation
  ...)

现在我想根据传入的数据/上下文生成元组。我尝试了很多不同的事情,但都没有成功。例如

(let [this (repository/u "http://example.com/ACMECorp")
      statements (repository/find-by-subject this)
      context {:depth 1}]
  `(at (snippet-for 'this 'context)
       [root] (set-attr :about (str 'this))
       ~@(loop [rules []
                st statements]
           (if-not (seq st)
             rules
             (recur (conj rules
                          `[:> (attr= :property ~(str (repository/predicate (first st))))]
                          `(content (renderit ~(repository/object (first st)) 'context)))
                    (rest st))))))

非常感谢任何帮助。

-乔辰

【问题讨论】:

  • 我建议查看宏扩展。在 repl:macroexpand-1;在 SLIME 中:slime-macroexpand-1。可能是您创建的表单不正确。

标签: macros clojure enlive


【解决方案1】:

Clojure 是一个 Lisp,因此您可以随时退回到构建您想要的代码作为列表,并在其上调用 eval。我不能 100% 确定您提供的代码,但我猜您只想将整个语法引用包含在 eval 调用中。

(let [this (repository/u "http://example.com/ACMECorp")
      statements (repository/find-by-subject this)
      context {:depth 1}]
  (eval `(at (snippet-for 'this 'context)
             [root] (set-attr :about (str 'this))
             ~@(loop [rules []
                      st statements]
                 (if-not (seq st)
                   rules
                   (recur (conj rules
                                `[:> (attr= :property ~(str (repository/predicate (first st))))]
                                `(content (renderit ~(repository/object (first st)) 'context)))
                          (rest st)))))))

【讨论】:

  • 是的,eval 解决了这个问题。我也做了一些错误的引用。使用 at* 形式也是一个难题。谢谢!
【解决方案2】:

不确定它们是否可以互换,但请看一下 at* 函数。在我看来,您的问题在于宏。

编辑:他们不是。像这样称呼它:

(at* a-node
  [[:a :selector] a-transformation
   [:another :selector] another-transformation
   ...])

【讨论】:

  • 感谢您的照顾。 (at {:tag :p} [:p] (content "foo")) 按预期给了我({:content ("foo"), :tag :p})。不幸的是(at* {:tag :p} [[:p] (content "foo")]) 抛出“不知道如何从:clojure.lang.Keyword 创建 ISeq”。
猜你喜欢
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
相关资源
最近更新 更多