In Clojure, you need to use gensym
to create symbols for internal use in your macros to keep them hygienic. However, sometimes you need to use the same symbol in nested syntax-quotes. For example, if I want to bind a value to a symbol with let
and print it three times in an unrolled loop, I'd do
`(let [x# 1]
~@(repeat 3
`(println x#)))
But that would produce
(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#
generates a different symbol in the let
form than in the println
forms nested within it - because they were created from different syntax-quotes.
To solve it, I can generate the symbol beforehand and inject it to the syntax-quotes:
(let [x (gensym)]
`(let [~x 1]
~@(repeat 3
`(println ~x)))
)
This will produce the correct result, with the same symbol everywhere needed:
(clojure.core/let [G__7 1]
(clojure.core/println G__7)
(clojure.core/println G__7)
(clojure.core/println G__7))
Now, while it does produce the right result, the code itself looks ugly and verbose. I don't like having to "declare" a symbol, and the injection syntax makes it look like it came from outside the macro, or calculated somewhere within in it. I want to be able to use the auto-gensym syntax, which makes it clear that those are macro-internal symbols.
So, is there any way to use auto-gensym with nested syntax-quotes and make them produce the same symbol?