我对Clojure的compojure库中的一些代码有疑问。
(defn compile-route
"Compile a route in the form (method path & body) into a function."
[method route bindings body]
`(make-route
~method ~(prepare-route route)
(fn [request#]
(let-request [~bindings request#] ~@body))))
我只看到了宏的上下文中使用的gensyms,它们用于防止宏中使用的绑定和本地作用域中的绑定之间的冲突。
我认为,由于以上是一个功能,而不是宏,它对此免疫。因此,我想知道像宏一样编写这个函数的理由是什么。
(如果你想知道,我检查了提交历史记录,看看这个函数最初是作为宏写的。不是。)
答案 0 :(得分:5)
Gensyms(至少-#
符号)不是在宏的上下文中使用,而是在反引号的上下文中使用。为了或多或少地确保macro hygiene,不能解析为全局限定符号的符号不能在反引号上下文中使用。虽然这不是强制执行的,但如果您真的想要一个不合格的符号,则会有一个逃生舱,它提供了一个理智的默认值。有关Clojure中宏观卫生的更长篇讨论,请参阅this博客文章。
答案 1 :(得分:3)
虽然你看到的是一个函数而不是一个宏,但它是一个生成Clojure代码的函数。 (它几乎肯定会从宏中调用。)并且,它不仅生成代码,而且插入代码,该代码作为body
参数传入生成的代码中。这就是为什么它需要通过gensym来避免名字冲突。
虽然它不是一个宏,但是它做了与宏相同的事情,它使用gensym的原因完全相同。