为什么需要多个命名空间?
在 Common Lisp 中为值和函数设置单独的命名空间的设计决策背后的基本原理是什么?支持和反对的理由是什么?
What is the rationale behind the design decision to have separate namespaces for values and functions in Common Lisp? What are the arguments for and against it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
请参阅 Richard P. Gabriel 的论文 功能单元和价值单元分离的技术问题 对这个主题进行全面的学术处理。
Please see Richard P. Gabriel's paper Technical Issues of Separation in Function Cells and Value Cells for a full academic treatment of this subject.
Common Lisp 基本上是原始 Lisp 1.5 的后代,或者更确切地说,是其不同方言的统一。最初的 Lisp 1.5 就是现在所说的 Lisp-2。因为那是六十年代的事,你可以将函数传递给其他函数这一事实已经够奇怪的了。没有人会想到让它们共享相同的命名空间。当今发明的几乎所有支持高阶函数和匿名函数的语言都选择单命名空间方法。包括 Clojure,它在其他方面更接近 Common Lisp,而不是 Scheme。
与 Clojure 一样,Scheme 最初并不是与 Lisp 1.5 不同的方言,而且就它们的目的而言,它是有意义的。
当然,在 Clojure 中,向量、哈希映射、集合以及所有这些也可以应用于参数,因此在某种意义上,Clojure 中的向量可以被视为一个函数,它接受一个自然数并从中生成一个值。
Common Lisp is basically a descendant from the original Lisp 1.5, or rather, a unification of its diverging dialects. The original Lisp 1.5 was what is nowadays called a Lisp-2. Because it was back in the sixties and the fact that you could pass functions to other functions was weird enough. No one would even think of letting them share the same namespace. Almost any language invented today with support for higher order functions and anonymous functions chooses the single-namespace approach. Including Clojure, which is otherwise closer to Common Lisp than to Scheme.
Scheme, like Clojure, wasn't originally a divergent dialect from Lisp 1.5, and for their purposes it makes sense.
Of course, in Clojure, vectors, hash maps, sets and all that can also be applied to arguments, so in a sense a vector in Clojure could be seen as a function that takes a natural number and produces a value from that.
尽管理论上可能有很多争论,但我敢打赌它的起源很大程度上是哲学上的。 Schema 是一种 Lisp-1,它更喜欢优雅而不是实用性,并为变量和函数选择相同的
define
语法,这使得单个名称空间感觉很自然(并鼓励函数式编程风格)。 Common Lisp 倾向于实用性和强大功能而不是优雅,并且是建立共识的尝试,因此看到现有的两个命名空间解决方案被广泛接受并且运行良好,就接受了它。然而,在实践中,它主要意味着三件事:
funcall
需要带有变量的函数名称;例如函数参数,例如
lst
而不是list
然而,这是为什么有些人更喜欢一种 Lisp 而不是另一种 Lisp 的一个主要因素。
Though there may be plenty of arguments each way in theory, I'd bet that it is largely philosophical in origin. Scheme, a Lisp-1, prefers elegance over practicality, and chose the same
define
syntax for variables and functions, which makes a single namespace feel natural (and encourages a functional style of programming). Common Lisp tends to prefer practicality and power over elegance, and was an attempt at consensus-building, so seeing an existing two-namespace solution broadly accepted and working well, accepted it.In practice, however, it mostly means three things:
funcall
a lotneeded function names with variables; e.g. function arguments like
lst
instead oflist
It is one major factor in why some people prefer one Lisp to another, however.
我实际上喜欢拥有多个命名空间(甚至超过两个);它使用户和编译器编写者(实现)变得更容易:
I actually like having several namespaces (more than two even); it makes things easier for the user and the compiler-writer (implementation):
除了上面提到的其他问题之外,为函数提供单独的命名空间使得 CL 不卫生的宏不太可能影响宏用户。在 CL 中,在宏扩展内出现的调用点绑定的名称将具有调用点使用的定义,而不是定义宏的地方使用的定义。因此,在 Lisp-1 版本的 CL 中,如果宏扩展为对 LIST 函数的调用,并且 LIST 在调用宏的位置被定义为变量,则宏将发生故障。 (请注意,gensym 不能解决这个问题,这与它们确实解决的逆问题不同。)
这在Scheme 中不会发生,因为默认情况下Scheme 宏是卫生的:宏扩展中使用的所有名称都具有它们的含义在定义宏的位置,而不是使用宏的位置。
In addition to the other issues mentioned above, having a separate namespace for functions makes CL's unhygienic macros much less likely to bite the macro user. In CL, a name bound at the point of call that appears within the expansion of a macro will have the definition used at the calling point, not the definition used where the macro is defined. So in a Lisp-1 version of CL, if a macro expands to a call on the LIST function, and LIST were defined as a variable at the point where the macro was called, the macro would malfunction. (Note that gensyms don't solve this problem, unlike the inverse problem which they do solve.)
This doesn't happen in Scheme because by default Scheme macros are hygienic: all the names used in the expansion of a macro have the meanings they had where the macro is defined, not where it is used.