【问题标题】:In clojure, how can I evaluate the arguments to a macro from another macro?在 clojure 中,如何从另一个宏评估宏的参数?
【发布时间】:2011-07-12 16:25:19
【问题描述】:

我有两个宏。第一个将符号作为唯一参数(因为它被传递给 def,它需要一个符号)。第二个函数需要一个符号列表,并且应该单独调用第一个符号和每个符号。

(defmacro m1 [s]
  '(let [f# ... dynamic function definition ...]
      (def ~s f#))

第二个宏应该获取一个符号列表并将它们传递给第一个,但我无法让它工作。我能想到的最好的方法如下:

(defmacro m2 [symbols]
   `(for [s# ~symbols] (eval (read-string (str "(name.of.current.namespace/m1 " s# ")")))))

这会强制 s# 在传递给第一个宏之前对其进行评估。它也被一个字符串列表调用,而不是一个符号列表。

这对于我正在使用的库很有用,该库中的所有函数都采用相同的两个第一个参数。我正在尝试在我的命名空间中为一些函数创建包装函数,这些函数会自动提供前两个参数值,它们都是通用的。

有什么改进的方法吗?

【问题讨论】:

  • 为什么这里不能选择普通的 fn?类似于(defn m2fun [symbols] (map m1 symbols))
  • 你可以只使用部分吗?我真的不明白问题出在哪里。

标签: macros clojure


【解决方案1】:

通常当你问如何让两个宏协同工作时,答案是不要让它们都成为宏。我认为我在macro-writing macros 上的博客文章将有助于澄清。对于这种特殊情况,我可能会结合 cmets 的两个建议:

(defmacro build-simpler-functions [& names]
  (cons 'do
        (for [name names]
          `(def ~(symbol (str "simple-" name))
             (partial ~name 5 10))))) ; if you always pass 5 and 10

(build-simpler-functions f1 f2)

这扩展为

(do
  (def simple-f1 (clojure.core/partial f1 5 10))
  (def simple-f2 (clojure.core/partial f2 5 10)))

这看起来基本上是你想要的。

编辑:如果你“总是”传递的参数对于每个函数都不同,你可以这样做:

(defmacro build-simpler-functions [& names]
  (cons 'do
        (for [[name & args] names]
          `(def ~(symbol (str "simple-" name))
             (partial ~name ~@args)))))

(build-simpler-functions [f1 5 10] [f2 "Yo dawg"]) ; expansion similar to the previous

【讨论】:

  • 这是正确的: (cons 'do ...) 和 ~(symbol s#...) 做到了。令人费解的是正在执行哪些代码,正在返回哪些代码以及它们如何相互影响的想法。
  • 您可能还喜欢 clojure.contrib.macro-utils.macrolet 用于这样的一次性宏。我不喜欢用我只使用一次的宏来污染我的命名空间,所以你可以写 (macrolet [(defpartial [& funcs] (cons 'do ...))] (defpartial [f1 5 10] [f2 'omg '更多 'args]))
猜你喜欢
  • 2011-10-21
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 1970-01-01
相关资源
最近更新 更多