一个命名空间为什么会导致LISP中不卫生的宏?

8

1
由于你已经等待三个小时却没有得到任何(真正的)答案:你可以尝试在“Lambda the Ultimate”上提问。你可能会被踢出该列表,因为它实际上是关于编程语言研究的,但那里的人一定可以回答你的问题。http://lambda-the-ultimate.org/ - Eike
1个回答

7

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

这意味着你在宏中不太可能无意中重新绑定函数值(或变量值)。

在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)

以下是一些变量卫生的建议:

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"

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

4
实际上,“rev”宏的工作原理大多依赖于Clojure自动解析语法引用形式中字面量引入的符号以及命名空间限定符号可能无法命名本地变量的事实(reverse在扩展中实际上变成了clojure.core/reverse(let [reverse :foo] (rev ...))不是问题,因为“rev”形式的扩展从未提到“reverse”--它使用的是“clojure.core/reverse”)。据我所知,这是Clojure对宏卫生性讨论的创新贡献。 - Michał Marczyk
3
当然,“gensym”在这里是非常重要的,但是一个包系统(“package”是Common Lisp的术语;在Clojure中,“namespace”用来表示)对于非卫生宏的合理性也是至关重要的。Clojure的自动解析是一种特别聪明的方式,可以最大限度地提供帮助。 - Michał Marczyk
2
我完全忘记了语法引用会完全解析它所包含的符号:谢谢你提醒我!我认为我的答案是正确的,但这是一个重要/有趣的事情需要注意。实际上,在我回答这个问题的早期版本中,我就利用了这一点:https://dev59.com/OnA75IYBdhLWcg3wFE6b 再次感谢Michal澄清事情。 - Isaac
1
非常好的评论。我可以补充一下,在Clojure邮件列表上有一个线程,Rich Hickey在其中解释了Clojure宏的独特性:http://groups.google.com/group/clojure/msg/7c10f217778ec877 - user445161

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接