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