鉴于下面的宏 -
(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。也许这有点困难,但这让你知道宏是如何工作的。