从符号列表构造clojure宏的正确方法是什么?

时间:2014-03-20 16:24:24

标签: macros clojure

想象一下动态创建宏的以下代码:

(def a (list '+ 1 2))
(def b (list '- 10 5))
(def c (list '/ 22 2))

(defmacro gg [h]
  (let [k# `~h]
     k#))

目的是将符号向量传递给宏,对向量的每个元素进行一些评估,使其返回一个漂亮的宏格式,然后让宏将它们组合成一个漂亮的宏并对其进行评估。除了实际评估之外,上面的示例都有效。

当我跑步时,我得到:

(gg [a b c])
=> [(+ 1 2) (- 10 5) (/ 22 2)]

传递符号列表并获取宏来评估符号的秘诀是什么?我已经尝试了很多引用的组合,但尚未找到正确的组合。

此问题的真正目的是根据图表中路径的定义构建Archimedes Ogre查询。如果有人有这方面的例子,我将不胜感激。

编辑:

(defmacro gg2 [h]
  `(do ~@(map identity h)))

(macroexpand '(gg2 [a b c]))
=> (do a b c)

(gg2 [a b c])
=> (/ 22 2)

我希望得到11而不是表格。

1 个答案:

答案 0 :(得分:3)

你不需要宏。宏不会做你在这里寻找的东西。您要找的是eval

(def a '/)
(def b 22)
(def c 2)
(eval (list* [a b c]))
=> 11

当然,如果需要,您可以编写一个扩展为(eval (list* ...))的宏。它也可以是一个功能。

这是开始使用宏时非常常见的错误;尝试编写一个宏,该宏依赖于其参数的运行时值。宏在编译时运行,通常在扩展宏时,传递给宏的符号值仍然不可用。

关于eval的使用,请注意一些注意事项。没有人说比保罗格雷厄姆更好:

通常,在运行时调用eval不是一个好主意,原因有两个:

这是低效的:eval被传递给原始列表,要么必须在现场编译,要么在解释器中进行评估。无论哪种方式都比预先编译代码慢,只是调用它。

它的功能不那么强大,因为表达式的评估没有词汇上下文。除此之外,这意味着您不能引用在被评估的表达式之外可见的普通变量。

通常,明确地调用eval就像在机场礼品店购买东西一样。等到最后一刻,你必须为有限的二流商品支付高价。