什么是单个命名空间导致不卫生的宏?(在LISP中)

haw*_*eye 8 lisp macros scheme clojure hygiene

有人声称LISP中的单个命名空间会导致不卫生的宏. http://community.schemewiki.org/?hygiene-versus-gensym

http://www.nhplace.com/kent/Papers/Technical-Issues.html

具有导致宏观卫生的单个,双重或多个名称空间究竟是什么?

Isa*_*aac 7

Lisp-2意味着你有两个名称空间:一个用于函数,一个用于其他东西.

这意味着您不太可能在宏中重新绑定宏中的函数值(或var值).

在Lisp-1中,由于有一个命名空间,因此(统计上,但实际上不是)命中现有定义的可能性是其两倍.

实际上,Lisp-1具有卫生覆盖的类似物gensym和Scheme的令人困惑的各种类似syntax-structure的宏,可以保持卫生.

我可以说,问题主要是一个稻草人的论点:它只是较贫穷或较旧的实施中的一个问题.

Clojure提供卫生宏gensym或读取器宏myvar#(#基本上是gensym).

而且你不必担心本地范围在你的宏中重新绑定你的函数:Clojure都是干净的:

user=> (defmacro rev [xs] `(reverse ~xs))
#'user/rev
user=> (rev [1 2 3])
(3 2 1)
user=> (let [reverse sort] (rev [1 2 5 3 6]))
(6 3 5 2 1)
Run Code Online (Sandbox Code Playgroud)

这里有一些可变卫生:

user=> (defmacro k [] (let [x# "n"] x#))
#'user/k
user=> (k)
"n"
user=> (let [x "l"] (k))
"n"
user=> (let [x "l"] (str (k) x))
"nl"
Run Code Online (Sandbox Code Playgroud)

请注意我们性感的gensym'd x#.

  • 实际上`rev`宏的工作主要是因为Clojure如何在语法引用形式中自动解析由文字引入的符号,以及命名空间限定的符号可能不会命名本地的事实(`reverse`实际上变成`clojure.core/reverse`在扩展中;`(让[reverse:foo](rev ...))`不是问题,因为`rev`形式的扩展从未提到`reverse` - 它提到了`clojure.core/reverse`).据我所知,这是Clojure对宏观卫生辩论的创新贡献. (4认同)
  • 当然`gensym`s在这里绝对至关重要,但是一个包系统(包是CL lingo;这就是Clojure土地中使用的"命名空间"这个词)也是非卫生宏观健全的基础,而Clojure的autoresolving是一个特别聪明的方法是尽可能地帮助它. (3认同)
  • 我完全忘记了语法引用完全解析了它所包含的符号:谢谢你!我认为我的答案是正确的,但这是一个重要/有趣的事情需要注意.在我对这个问题的回答的早期迭代中,我实际上利用了这一点:http://stackoverflow.com/questions/3480377/clojure-namespace-management-is-there-a-way-to-save-and-restore -the-state-of-c再次感谢Michal清理事宜. (2认同)