11

鉴于下面的宏 -

(defmacro defhello [fn-name body]   `(defn ~fn-name [~'name] ~body))

以及在调用时定义的函数 -

(defhello 问候语 (str "Hello" name))

并称为

(问候“乔”)

, 将返回

Hello Joe

不明白name参数前面~'的用法?它有什么作用?不要引号(')和取消引号(〜)相互取消?当它们一起使用时会发生什么?为什么不写名字没有他们呢?

4

3 回答 3

9

简而言之,~就像它对~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函数不存在。

于 2012-09-10T15:40:22.913 回答
2

据我了解,您引用了函数定义,因此在定义宏时不会对其进行评估。您使用 unquote operator~来评估定义中的 name。如果 name 是一种列表~@(不带引号的拼接),则将评估列表中的元素而无需使用括号。

于 2012-09-10T13:25:11.820 回答
1

名称前的引号用于防止符号限定。

如果您不知道什么是合格的,请参阅阅读器

此外,您可以使用macroexpand进行宏调试。

如果您想了解更多关于宏的信息,我建议您阅读On Lisp。也许这有点困难,但这让你知道宏是如何工作的。

于 2012-09-10T15:53:05.073 回答