想象一下动态创建宏的以下代码:
(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
而不是表格。
答案 0 :(得分:3)
你不需要宏。宏不会做你在这里寻找的东西。您要找的是eval
。
(def a '/)
(def b 22)
(def c 2)
(eval (list* [a b c]))
=> 11
当然,如果需要,您可以编写一个扩展为(eval (list* ...))
的宏。它也可以是一个功能。
这是开始使用宏时非常常见的错误;尝试编写一个宏,该宏依赖于其参数的运行时值。宏在编译时运行,通常在扩展宏时,传递给宏的符号值仍然不可用。
关于eval
的使用,请注意一些注意事项。没有人说比保罗格雷厄姆更好:
通常,在运行时调用eval不是一个好主意,原因有两个:
这是低效的:eval被传递给原始列表,要么必须在现场编译,要么在解释器中进行评估。无论哪种方式都比预先编译代码慢,只是调用它。
它的功能不那么强大,因为表达式的评估没有词汇上下文。除此之外,这意味着您不能引用在被评估的表达式之外可见的普通变量。
通常,明确地调用eval就像在机场礼品店购买东西一样。等到最后一刻,你必须为有限的二流商品支付高价。