31

Scheme 为所有变量使用一个命名空间,无论它们是绑定到函数还是其他类型的值。Common Lisp 将两者分开,因此标识符“hello”在一个上下文中可能指代一个函数,而在另一个上下文中指代一个字符串。

(注1:这个问题需要上面的一个例子;随意编辑它并添加一个,或者用它给原作者发电子邮件,我会这样做。)

但是,在某些情况下,例如将函数作为参数传递给其他函数,程序员必须通过使用明确区分他指定的是函数变量,而不是非函数变量,#'如下所示:

(sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first)

我一直认为这有点像疣,但我最近遇到了一个论点,认为这实际上是一个特性:

...重要的区别实际上在于形式的语法,而不是对象的类型。在不知道所涉及的运行时值的情况下,很明显函数形式的第一个元素必须是函数。CL 接受了这一事实并将其与宏和特殊形式一起成为语言的一部分,这些形式也可以(并且必须)静态确定。所以我的问题是:当函数名的主要用途是出现在变量名很少出现的地方时,为什么你希望函数名和变量名在同一个命名空间中?
考虑类名的情况:为什么一个名为 FOO 的类要阻止使用名为 FOO 的变量?我唯一一次用 FOO 来引用这个类是在需要类名的上下文中。如果在极少数情况下我需要获取绑定到类名 FOO 的类对象,则可以使用 FIND-CLASS。

从经验来看,这个论点对我来说确实有意义。Haskell 中也有类似的情况,字段名称也是用于访问字段的函数。这有点尴尬:

data Point = Point { x, y :: Double {- lots of other fields as well --} }
isOrigin p = (x p == 0) && (y p == 0)

这可以通过一些额外的语法来解决,NamedFieldPuns扩展特别好:

isOrigin2 Point{x,y} = (x == 0) && (y == 0)

那么,对于这个问题,除了一致性之外,Common Lisp 与 Scheme 以及一般而言,所有值的单个命名空间与函数和非函数值的单独命名空间的优点和缺点是什么?

4

6 回答 6

24

这两种不同的方法有名称:Lisp-1 和 Lisp-2。Lisp-1 对变量和函数都有一个命名空间(如在 Scheme 中),而 Lisp-2 对变量和函数有单独的命名空间(如在 Common Lisp 中)。我提到这一点是因为您可能不知道该术语,因为您没有在问题中提及它。

维基百科提到了这场辩论

单独的函数命名空间是否是一个优势是 Lisp 社区争论的根源。它通常被称为 Lisp-1 与 Lisp-2 的辩论。Lisp-1 指的是 Scheme 的模型,Lisp-2 指的是 Common Lisp 的模型。这些名称是由 Richard P. Gabriel 和 Kent Pitman 在 1988 年的一篇论文中创造的,该论文广泛比较了这两种方法。

Gabriel 和 Pitman 的题为“功能细胞和价值细胞分离的技术问题”的论文解决了这个问题。

于 2009-06-20T05:09:25.660 回答
12

实际上,正如Richard Gabriel 和 Kent Pitman 在论文中所概述的那样,争论是关于 Lisp-5 与 Lisp-6 的,因为已经存在其他几个命名空间,论文中提到了类型名称、标记名称、块名称和声明名称。 编辑:这似乎是不正确的,正如 Rainer 在评论中指出的那样:Scheme 实际上似乎是一个 Lisp-1。但是,以下内容在很大程度上不受此错误的影响。

一个符号是表示要执行的东西还是要引用的东西,从上下文中总是很清楚。将函数和变量放入同一个命名空间主要是一种限制:程序员不能对事物和动作使用相同的名称。Lisp-5 从中得到的只是避免了从不同于当前上下文所暗示的命名空间中引用某些东西的一些语法开销。 编辑:这不是全貌,只是表面。

我知道 Lisp-5 的支持者喜欢函数是数据这一事实,并且这在语言核心中得到了表达。我喜欢这样一个事实,即我可以将列表称为“列表”并将汽车称为“汽车”,而不会混淆我的编译器,而且函数无论如何都是一种从根本上特殊的数据。 编辑:这是我的主要观点:单独的命名空间根本不是一个缺点。

我也喜欢Pascal Constanza 对此的看法

于 2009-06-20T15:08:26.380 回答
2

我在 Python(统一命名空间)与 Ruby(方法与非方法的不同命名空间)中遇到了类似的区别。在这种情况下,我更喜欢 Python 的方法——例如,使用这种方法,如果我想列出一些东西,其中一些是函数,而另一些不是,我不必对它们的名称做任何不同的事情,例如,取决于它们的“功能性”。类似的考虑适用于函数对象被捆绑而不是调用的所有情况(高阶函数的参数和返回值等)。

也可以调用非函数(如果它们的类定义__call__,在 Python 的情况下——“运算符重载”的一种特殊情况),因此“上下文区别”也不一定清楚。

然而,我的“lisp-oid”体验主要是/曾经是使用 Scheme 而不是 Common Lisp,所以我可能会潜意识地对最终来自该体验的统一命名空间的熟悉程度产生偏见。

于 2009-06-20T05:06:53.277 回答
2

Scheme中的函数名只是一个以函数为值的变量。无论我是否这样做(define x (y) (z y))(let ((x (lambda (y) (z y))))我都在定义一个可以调用的函数。因此,就Scheme 而言,“变量名很少希望出现在那里”的想法有点似是而非。

Scheme 是一种典型的函数式语言,因此将函数视为数据是其原则之一。让函数成为自己的一种类型,像所有其他数据一样存储是实现这一想法的一种方式。

于 2009-06-20T06:27:46.930 回答
1

至少对于 Common Lisp,我看到的最大缺点是可理解性。我们都同意它为变量和函数使用不同的命名空间,但它有多少?在 PAIP 中,Norvig 表明它有“至少七个”命名空间。

当语言的经典书籍之一,由一位备受推崇的程序员撰写,在出版的书中甚至不能肯定地说,我认为有问题。我对多个命名空间没有问题,但我希望该语言至少足够简单,以至于有人可以完全理解它的这一方面。

我很乐意为变量和函数使用相同的符号,但在更晦涩的领域,我出于恐惧而使用不同的名称(冲突的命名空间真的很难调试!),这真的不应该是案子。

于 2009-06-22T17:34:04.120 回答
0

这两种方法都有好处。但是,我发现在重要的时候,我更喜欢同时拥有一个函数 LIST 和一个变量 LIST,而不是不得不错误地拼写其中一个。

于 2009-06-21T20:00:52.057 回答