在 Clojure 中,您需要gensym
在宏中创建供内部使用的符号,以保持它们的卫生。但是,有时您需要在嵌套语法引号中使用相同的符号。例如,如果我想将一个值绑定到一个符号,let
并在展开的循环中打印三次,我会这样做
`(let [x# 1]
~@(repeat 3
`(println x#)))
但这会产生
(clojure.core/let [x__2__auto__ 1]
(clojure.core/println x__1__auto__)
(clojure.core/println x__1__auto__)
(clojure.core/println x__1__auto__))
x#
let
在表单中生成与嵌套在其中的表单不同的符号println
- 因为它们是从不同的语法引号创建的。
为了解决它,我可以预先生成符号并将其注入到语法引号中:
(let [x (gensym)]
`(let [~x 1]
~@(repeat 3
`(println ~x)))
)
这将产生正确的结果,在任何地方都需要相同的符号:
(clojure.core/let [G__7 1]
(clojure.core/println G__7)
(clojure.core/println G__7)
(clojure.core/println G__7))
现在,虽然它确实产生了正确的结果,但代码本身看起来既丑陋又冗长。我不喜欢必须“声明”一个符号,并且注入语法使它看起来像是来自宏外部,或者在其中某处计算。我希望能够使用 auto-gensym 语法,这清楚地表明这些是宏内部符号。
那么,有没有办法使用带有嵌套语法引号的 auto-gensym 并使它们产生相同的符号?