(gensym)总是独一无二的,`(symb#)不是 - 为什么?

gal*_*dre 9 clojure

如果我编写一个使用symb#快捷方式创建gensym然后绑定为全局变量的宏,则会反复生成完全相同的符号.但是,如果我gensym手动调用它可以正常工作.很简单的例子:

(defmacro indirection
    [name & body]
    `(do (def name# ~@body)
         (defn ~name [] name#)))

(indirection foo 3)
(foo) ; ? 3
(indirection goo 5)
(goo) ; ? 5
(foo) ; ? 5
Run Code Online (Sandbox Code Playgroud)

如果你使用macroexpand以下问题很明显:

(macroexpand '(indirection foo 3))
(do (def name__2863__auto__ 3) (clojure.core/defn foo [] name__2863__auto__))
(macroexpand '(indirection foo 3))
(do (def name__2863__auto__ 3) (clojure.core/defn foo [] name__2863__auto__))
Run Code Online (Sandbox Code Playgroud)

如果我gensym长途跋涉,这个问题就会消失:

(defmacro redirection
    [name & body]
    (let [rename (gensym)]
        `(do (def ~rename ~@body)
             (defn ~name [] ~rename))))

(redirection koo 3)
(koo) ; ? 3
(redirection moo 5)
(moo) ; ? 5
(koo) ; ? 3
Run Code Online (Sandbox Code Playgroud)

那么,为什么差异呢?我错过了什么?

Ale*_*lex 13

语法引用`实际上是一个读者宏 ; 在评估之前,读者将其后面的形式转换(将文本翻译成Clojure形式).这意味着#当首次读取文本时,在语法引用中结束的任何符号仅被转换为自动生成的符号一次; 然后,自动生成的符号将直接插入到宏定义中,并在每次调用该宏时在宏遍历中逐字显示.这可以在REPL轻松说明:

user=> `(foo bar#)
(user/foo bar__2288__auto__)
user=> `(foo bar#)
(user/foo bar__2291__auto__)
Run Code Online (Sandbox Code Playgroud)

自动生成符号的典型用例#是在引号letfn表单内定义局部变量.在那里,重复使用相同的符号进行多次宏调用并不重要; 它只需要在每次调用中都是唯一的.例如:

(defmacro indirection
  [name body]
  `(let [name# ~body]
     (defn ~name [] name#)))
Run Code Online (Sandbox Code Playgroud)

  • 啊,哈.我很接近,但我专注于`foo #`而不是`````.非常感谢! (2认同)