首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >(gensym)总是唯一的,‘(symb#)不是--为什么?

(gensym)总是唯一的,‘(symb#)不是--为什么?
EN

Stack Overflow用户
提问于 2015-04-14 19:17:20
回答 1查看 410关注 0票数 9

如果我编写了一个宏,它使用symb#快捷方式创建一个gensym,然后将其绑定为一个全局变量,则会一次又一次地生成完全相同的符号。但是,如果手动调用gensym,它将正确运行。非常简单的例子:

代码语言:javascript
复制
(defmacro indirection
    [name & body]
    `(do (def name# ~@body)
         (defn ~name [] name#)))

(indirection foo 3)
(foo) ; ⇒ 3
(indirection goo 5)
(goo) ; ⇒ 5
(foo) ; ⇒ 5

如果使用macroexpand,问题就很明显。

代码语言:javascript
复制
(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__))

如果我用很长的方式调用gensym,这个问题就会消失:

代码语言:javascript
复制
(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

那么,为什么会有区别?我遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-14 19:48:33

使用`引用的语法实际上是一个reader macro;它后面的形式在计算之前由读取器(它将文本转换为Clojure表单)进行转换。这意味着在语法引用中以#结尾的任何符号在文本第一次读取时只被翻译成自动生成的符号一次;然后自动生成的符号将直接插入到宏定义中,并在每次调用宏时逐字显示在宏扩展中。在REPL中可以很容易地说明这一点:

代码语言:javascript
复制
user=> `(foo bar#)
(user/foo bar__2288__auto__)
user=> `(foo bar#)
(user/foo bar__2291__auto__)

带有#的自动生成符号的典型用例是在引用的letfn表单中定义局部变量。在那里,同样的符号被重新用于多个宏调用并不重要;它只需要在每次调用中都是唯一的。例如:

代码语言:javascript
复制
(defmacro indirection
  [name body]
  `(let [name# ~body]
     (defn ~name [] name#)))
票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29635646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档