我有一个简单的宏:
(defmacro macrotest [coll]
`(let [result# ~(reduce + coll)]
result#))
为什么这段代码有效:
(macrotest [1 2 3])
这段代码为什么不能工作?
(def mycoll [1 2 3])
(macrotest mycoll)
我有一个简单的宏:
(defmacro macrotest [coll]
`(let [result# ~(reduce + coll)]
result#))
为什么这段代码有效:
(macrotest [1 2 3])
这段代码为什么不能工作?
(def mycoll [1 2 3])
(macrotest mycoll)
符号并不等同于它们所指向的值。
关于宏的一个重要考虑因素不仅是它们如何创建新代码,还包括它们如何处理传递进来的参数。
请考虑以下内容:
(def v [1 2 3])
(somefunction v)
传递给此函数的参数v
不会作为符号v
到达函数内部。相反,因为这是一个函数调用,首先对参数进行求值,然后将其结果值传递到函数中。因此,函数将看到[1 2 3]
。
但是宏不是这样的,尽管很容易忘记。当您调用:
(somemacro v)
v
不会被求值,也不会传入[1 2 3]
。在宏内部,你得到的只是一个符号v
。现在,您的宏可以在它创建的代码中发出您传递的符号,但是除非您使用eval
(请参见脚注--不建议使用)添加额外的求值级别,否则它无法处理v
的值。
当您取消引用宏参数时,您得到的是一个符号,而不是一个值。
请考虑以下示例:
user> (def a 5)
#'user/a
user> (defmacro m [x] `(+ ~x ~x))
#'user/m
user> (m a)
10
user> (macroexpand '(m a))
(clojure.core/+ a a)
user> (defmacro m [x] `~(+ x x))
#'user/m
user> (m a)
ClassCastException clojure.lang.Symbol cannot be cast to java.lang.Number clojure.lang.Numbers.add (Numbers.java:126)
(+ 'a 'a)
,它是将符号相加,而不是将这些符号指向的值相加。x
进行加法操作。在第一个宏定义中,编译器没有被要求对x进行任何操作,它只是被告知需要输出加法运算,这将在运行时实际处理。eval
),所以很容易忽略这种分离,但它们是两个不同的步骤。(* t w)
好的?这是不可能的。您无法回答这个问题,因为您不知道t
和w
是什么。然而,在稍后运行时,当它们预计具有值时,这将变得容易。