繁体   English   中英

Clojure宏:解析var

[英]Clojure macros: resolving vars

我似乎可以将头放在Clojure中的宏周围。 我可能缺少一些基本的知识。 首先,让我描述一个我想要的例子。

(defmacro macrotest [v] `(d ...))
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (d (b c))

换句话说,传递给macrotestvar已解析,但未进行进一步评估。

向宏提供var的值的工作原理:

(defmacro macrotest [v] `(d ~v))
(macroexpand-1 '(macrotest (b c)))
; => (d (b c))

但是提供var不会:

 (def a '(b c))
 (macroexpand-1 '(macrotest a))
 ; => (d a)

是否可以在Clojure宏中解析var ,但不评估其值?

编辑:我想要什么似乎可以与eval

  (defmacro macrotest [v] `(d ~(eval v)))
  (def a '(b c))
  (macroexpand-1 '(macrotest a))
  ; => (user/d (b c))

重要的是要了解宏在编译时而不是在运行时求值

在编译时, var a还没有值,因此其值不会传递给宏,而仅传递给其名称。 但是,当您显式传递“值”时,那么它在编译时就存在,并且您会看到它“起作用”。

词汇环境

在宏内使用eval是不好的做法。 当然,可以进行以下工作:

(macroexpand-1 '(macrotest a))
; => (user/d (b c))

...但是,这不能按预期工作:

(macroexpand-1 '(let [a "oh no"]
                  (macrotest a)))
; => (user/d (b c))

当然,您希望宏对a本地定义的a进行求值,而不使用绑定到全局变量的全局变量,但是您不能这样做,因为宏没有在正确的词法上下文中求v 这是理解宏的关键:它们获取代码并生成代码; 该代码处理的所有数据尚不可用。 换句话说,宏扩展的时间可能与结果代码的评估时间完全无关:在宏执行过程中评估的任何内容都可能与数据的相关性过早评估。

你想让我做什么?

有一种名为macrotest的形式,该形式应接受参数v ,然后如果您已将形式d应用于它, macrotest执行。 但:

  • (macrotest (bc)) 不应评估(bc) ,只需将其原样复制即可产生(d (bc))
  • (macrotest a) 评估a ,结果以引号引起来,并将该形式放入结果代码中,并返回(d (bc))

您在这里遇到了问题,因为在一种或另一种情况下含义会发生根本变化。 要么评估一个参数,在这种情况下,您必须引用(bc)并编写:

(defmacro macrotest [v] `(d ~v))

...要求d准备好处理引用的参数; 否则您可以接受不评估的参数。 使用与上面相同的d ,可以显式引用参数:

(defmacro macrotest [v] `(d '~v))

但是,如果d本身是不计算其参数的宏,你必须避免在前面的报价~v

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM