鉴于下面的宏 -
(defmacro defhello [fn-name body] `(defn ~fn-name [~'name] ~body))
以及在调用时定义的函数 -
(defhello 问候语 (str "Hello" name))
并称为
(问候“乔”)
, 将返回
Hello Joe
不明白name参数前面~'的用法?它有什么作用?不要引号(')和取消引号(〜)相互取消?当它们一起使用时会发生什么?为什么不写名字没有他们呢?
鉴于下面的宏 -
(defmacro defhello [fn-name body] `(defn ~fn-name [~'name] ~body))
以及在调用时定义的函数 -
(defhello 问候语 (str "Hello" name))
并称为
(问候“乔”)
, 将返回
Hello Joe
不明白name参数前面~'的用法?它有什么作用?不要引号(')和取消引号(〜)相互取消?当它们一起使用时会发生什么?为什么不写名字没有他们呢?
简而言之,~
就像它对~fn-name
. 在这种情况下,要计算的表达式是'name
,其中的结果是不合格的符号name
。
但是,让我们一次分解一个。
如果您只有不合格的符号name
,它将clojure.core/name
在运行时评估为1。这将导致defn
格式不正确并导致编译器异常。
(defn greeting [clojure.core/name] (str "Hello" name))
如果您只有带引号的不合格符号'name
,它仍然会在运行时进行评估。不同之处在于它会扩展为(quote clojure.core/name)
. 同样,这将导致defn
格式不正确并导致编译器异常。
(defn greeting [(quote clojure.core/name)] (str "Hello" name))
最后,通过 using ~'name
,您将在编译时评估引用的形式,从而产生不合格的符号name
,从而为您留下正确的defn
形式。
(defn greeting [name] (str "Hello" name))
1 - 这个例子是正确的,因为它假设另一个name
函数不存在。
据我了解,您引用了函数定义,因此在定义宏时不会对其进行评估。您使用 unquote operator~
来评估定义中的 name。如果 name 是一种列表~@
(不带引号的拼接),则将评估列表中的元素而无需使用括号。
名称前的引号用于防止符号限定。
如果您不知道什么是合格的,请参阅阅读器。
此外,您可以使用macroexpand进行宏调试。
如果您想了解更多关于宏的信息,我建议您阅读On Lisp。也许这有点困难,但这让你知道宏是如何工作的。