在具有静态类型的语言中,“Lisp-1 vs Lisp-2”是否相关?

3
这是一个CS理论类型的问题,希望可以接受。 "Lisp-1 vs Lisp-2" 辩论是关于函数命名空间是否应该与所有其他变量的命名空间不同,在允许程序员将函数作为值传递的动态类型语言中很重要。Lisp-1语言(如Scheme)只有一个命名空间,因此您不能同时拥有名为f的函数和整数(一个会遮盖另一个,就像两个名为f的整数)。Lisp-2语言(如Common Lisp)有两个命名空间,因此您可以拥有两个f变量,但您必须使用特殊语法指定您想要的是哪一个(#'f是函数,f是整数)。
在我看来,主要的技术问题,即需要消除函数与整数之间的歧义,如果语言也是静态类型的(与大多数Lisp不同),则不是问题。例如,如果一个sort函数需要一个列表和一个显式签名的小于函数,
def sort[X](list: List[X], lessThan: Function[X, Boolean])    // Scala syntax; had to pick something

如果函数和其他所有东西在同一个命名空间中或不在同一命名空间中,则无所谓。只有当myless是一个函数时,sort(mylist,myless)才会通过类型检查---不需要特殊的语法。一些人认为一个命名空间比两个命名空间更美观,但我想重点讨论技术问题。
假设所涉及的语言是静态类型的,那么两个命名空间是否会使某些事情更加困难或更容易出错(反之亦然)?
(我正在考虑这个问题,在我工作的领域特定语言的上下文中,我想确保我将来不会遇到问题。使用两个命名空间(Lisp-2)实现会更容易,因为它是静态类型的,所以不需要等效于#'f。我提出了一般性的问题,因为我想听取一般性的观点,也许还能意识到我尚未知道的问题。)

所以你想根据类型选择使用Lisp-1还是Lisp-2?这似乎既令人困惑又容易出错。 - gsg
为什么实现Lisp-2会更容易呢?你提供的链接引用了类型检查的性能成本,但如果你的语言是静态类型的,就不会有这个问题。 - gsg
1个回答

9
有一个常见反对多个命名空间的观点是,它使有任意数量的命名空间的形式语义变得复杂。只有一个命名空间可以让事情变得简单。我听说下一个最简单的是无限数量的命名空间--我没写过这些东西,只尝试过一次,但只完成了其中的一半(如果你好奇可以看看这里,虽然我认为这不是你在这种情况下想要的)。据我所知,当限制为有限数量的命名空间时,形式语义变得混乱,或者至少如此。并且,这也使得任何类型的编译器或解释器更加复杂。这个反对意见介于美学和技术之间,因为它不是基于技术难度本身的反对意见,因为没有超人类的智力需要使用多个名称空间,只需要大量的额外手动工作,而是因为进行更复杂的语义意味着更多的代码、更多的特殊情况、更多的错误机会等等。就我个人而言,我并不被这样的论点所动摇,我只是指出它们,因为你问了。我认为你会发现这样的论点并不致命,可以继续进行你正在做的工作,看看它会带来什么。我更关心程序员/最终用户的体验,而不是实现者的难度。但是我提到这个参数,因为我尊重的其他人似乎认为这是一个大问题,我相信这是你对于困难和容易出错性的正确答案。
顺便说一下,当Gabriel和我写Function Cells and Value Cells中的分离的技术问题时,我需要用一些词来帮助我避免说“类Scheme”和“类Lisp”,因为人们喜欢Scheme有无关的原因,与命名空间无关。使用术语“Lisp1”和“Lisp2”允许我避免论文变成Scheme vs. Lisp的辩论,并将读者集中在命名空间的问题上。最终,ANSI Common Lisp至少具有4个命名空间(函数、值、go标签、块标签),或者如果您计算类型(在某些方面类似于命名空间但在其他方面则不然),那么也可能是5个,但无论如何都不是2。所以严格来说,它仍然是Lisp4或Lisp5。但无论哪种方式,它仍然使那些喜欢单个命名空间的人感到震惊,因为任何大于1的任意有限数量往往是不可接受的。
我的个人建议是,你应该根据你自己的观念设计语言。对于某些语言,只有一个命名空间就可以了。对于其他语言则不行。只要不是因为别人告诉你两种方式都是正确的方式--这真的是你可以自由选择的。
有人认为一个命名空间在概念上更简单,但我认为这取决于简单的概念。有些人说较小的东西更简单(符号或实现)。我认为,概念上最简单的是与您的大脑思考方式最相似的,而您的大脑并不总是在想“小”来表示“简单”。我会引用至少一个例子,即存在多个定义相同单词的每种人类语言,几乎都可以通过上下文(您的类型推断可能是上下文信息的一个示例)来解决,表明wetware被设计为消除这些问题,如果您不让它关心这些事情,则您的大脑浪费了一些其自然能力。也许这种上下文推理确实增加了您的语言实现的复杂性,但语言只实现一次,并且使用多次,因此应优化最终用户体验而不是实现者体验。这是一项后期收益的投资。

坚持按照您想要的方式思考事物。更担心使您的语言具有良好的感觉以及您想要做的事情是否可实现,即使它需要工作和额外的代码检查。对于每种语言设计决策,没有一种是适用于所有语言的正确决策-语言是生态系统,重要的是语言元素彼此良好配合,而不是语言元素与其他语言匹配。事实上,如果所有语言都将是相同的,那么拥有多种语言将毫无意义。


谢谢你详细的回答!在我提出问题后的这段时间里,我对此进行了更深入的思考,并意识到在静态类型语言中,类型的命名空间是另一个独立的命名空间---这些类型是在编译时评估的语言,与运行时评估的语言是不同的。因此,静态类型语言已经有了多个命名空间。相比之下,像Python这样的动态类型语言可以将类型放在与变量(例如类对象)相同的命名空间中。由于是一个对比于(有限的)多个,我会选择这种方式。 - Jim Pivarski
@Jim,你关于对象、模块和包像命名空间一样的评论让我想起了一点:宏、包和Lisp1/Lisp2之间有微妙的相互作用,我觉得这种相互作用使得Common Lisp不会遇到Scheme所面临的卫生问题。Schemers经常担心Lisp没有卫生宏就是致命缺陷。我不同意,但这毫无疑问是主观的。1998年,我在comp.lang.lisp上与已故的Erik Naggum详细讨论了这个问题。 - Kent Pitman

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