macro2
不打电话macro1
。看看它的身体:
`(macro1 ~x)
(func1 x)
第一行是语法引用的;它的值是表单的列表结构(user/macro1 x-value)
(假设macro1
定义在user
命名空间;x-value
这是提供给的字面参数macro2
)并且没有副作用。因为没有副作用并且该值被丢弃,所以该行没有任何效果。
回应编辑:
首先,区分很重要calling宏体内的另一个宏发出呼叫到另一个宏:
(defmacro some-macro []
...)
;; calls some-macro:
(defmacro example-1 []
(some-macro))
;; emits a call to some-macro:
(defmacro example-2 []
`(some-macro))
其次,在宏体内调用函数和宏的情况下,必须记住运行时和编译时的相关概念是什么:
如果一个宏发出对另一个宏的调用,则与发出的宏调用相关的运行时和编译时间的概念将与与原始宏调用相关的相同。如果一个宏调用另一个宏,它们就会向后移动一步,就像以前那样。
为了说明这一点,让我们考虑一个将其所有工作委托给辅助函数的宏:
(defn emit-abc [abc-name [a b c]]
`(def ~abc-name {:a ~a :b ~b :c ~c}))
(defmacro defabc [abc-name abc-vals]
(emit-abc abc-name abc-vals))
来自 REPL:
user> (defabc foo [1 2 3])
#'user/foo
user> foo
{:a 1, :c 3, :b 2}
If emit-abc
本身就是一个宏,上面的定义defabc
甚至无法编译,因为emit-abc
会尝试解构文字符号abc-vals
,抛出一个UnsupportedOperationException
.
这是另一个例子,可以更容易地解释正在发生的事情:
(let [[a b c] [1 2 3]]
(defabc foo [a b c]))
defabc
接收三个文字符号的向量a
, b
and c
作为第二个参数;它无法访问运行时值1
, 2
and 3
。它将这个精确的符号向量传递给函数emit-abc
,然后能够进入该向量并提取符号以生成地图{:a a :b b :c c}
。这张地图成为了defabc
称呼。运行时a
, b
and c
结果与值绑定1
, 2
and three
,所以地图{:a 1 :b 2 :c 3}
被生产。
假设我们尝试写emit-abc
作为具有相同主体的宏(只是改变defn
to defmacro
在其定义中)。然后我们就无法有效地从defabc
,因为我们没有任何方式向它传递参数的实际值defabc
。我们可以写
(emit-abc abc-name [(abc-vals 0) (abc-vals 1) (abc-vals 2)])
to make defabc
编译,但这最终会发出abc-name
作为正在定义的 Var 的名称并包含向量文字的代码[a b c]
在生成的代码中三次。然而我们可以向它发出一个调用:
`(emit-abc ~abc-name ~abc-vals)
这按预期工作。