Common Lisp 与 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 以及一般情况下,所有值的单个命名空间与函数和非函数值的单独命名空间?
Scheme uses a single namespace for all variables, regardless of whether they are bound to functions or other types of values. Common Lisp separates the two, such that the identifier "hello" may refer to a function in one context, and a string in another.
(Note 1: This question needs an example of the above; feel free to edit it and add one, or e-mail the original author with it and I will do so.)
However, in some contexts, such as passing functions as parameters to other functions, the programmer must explicitly distinguish that he's specifying a function variable, rather than a non-function variable, by using #'
, as in:
(sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first)
I have always considered this to be a bit of a wart, but I've recently run across an argument that this is actually a feature:
...the
important distinction actually lies in the syntax of forms, not in the
type of objects. Without knowing anything about the runtime values
involved, it is quite clear that the first element of a function form
must be a function. CL takes this fact and makes it a part of the
language, along with macro and special forms which also can (and must)
be determined statically. So my question is: why would you want the
names of functions and the names of variables to be in the same
namespace, when the primary use of function names is to appear where a
variable name would rarely want to appear?
Consider the case of class names: why should a class named FOO prevent
the use of variables named FOO? The only time I would be referring the
class by the name FOO is in contexts which expect a class name. If, on
the rare occasion I need to get the class object which is bound to the
class name FOO, there is FIND-CLASS.
This argument does make some sense to me from experience; there is a similar case in Haskell with field names, which are also functions used to access the fields. This is a bit awkward:
data Point = Point { x, y :: Double {- lots of other fields as well --} }
isOrigin p = (x p == 0) && (y p == 0)
This is solved by a bit of extra syntax, made especially nice by the NamedFieldPuns
extension:
isOrigin2 Point{x,y} = (x == 0) && (y == 0)
So, to the question, beyond consistency, what are the advantages and disadvantages, both for Common Lisp vs. Scheme and in general, of a single namespace for all values versus separate ones for functions and non-function values?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这两种不同的方法有名称:Lisp-1 和 Lisp-2。 Lisp-1 对变量和函数有一个单一的命名空间(如在Scheme 中),而Lisp-2 对变量和函数有单独的命名空间(如在Common Lisp 中)。 我提到这一点是因为您可能不知道该术语,因为您没有在问题中提到它。
维基百科引用了这场辩论:
Gabriel 和 Pitman 的论文,标题为功能单元和价值单元分离的技术问题解决了这个问题。
The two different approaches have names: Lisp-1 and Lisp-2. A Lisp-1 has a single namespace for both variables and functions (as in Scheme) while a Lisp-2 has separate namespaces for variables and functions (as in Common Lisp). I mention this because you may not be aware of the terminology since you didn't refer to it in your question.
Wikipedia refers to this debate:
Gabriel and Pitman's paper titled Technical Issues of Separation in Function Cells and Value Cells addresses this very issue.
实际上,正如 Richard Gabriel 和 Kent Pitman 的论文中所述,这场争论是关于 Lisp-5 的与 Lisp-6 相比,由于已经存在其他几个名称空间,因此论文中提到了类型名称、标记名称、块名称和声明名称。 编辑:这似乎是不正确的,正如 Rainer 在评论中指出的那样:Scheme 实际上似乎是 Lisp-1。 不过,以下内容很大程度上不受此错误的影响。
符号是否表示要执行的内容或要引用的内容总是可以从上下文中清楚地看出。 将函数和变量放入同一名称空间主要是一个限制:程序员不能对事物和操作使用相同的名称。 Lisp-5 从中得到的只是避免了从与当前上下文含义不同的名称空间引用某些内容的一些语法开销。 编辑:这不是全部图片,只是表面。
我知道 Lisp-5 支持者喜欢函数就是数据这一事实,并且这是在语言核心中表达的。 我喜欢这样一个事实:我可以将列表称为“列表”,将汽车称为“汽车”,而不会混淆我的编译器,而且函数无论如何都是一种根本上特殊的数据。 编辑:这是我的要点:单独的命名空间根本不是一个缺点。
我也喜欢Pascal Constanza 对此有何评论。
Actually, as outlined in the paper by Richard Gabriel and Kent Pitman, the debate is about Lisp-5 against Lisp-6, since there are several other namespaces already there, in the paper are mentioned type names, tag names, block names, and declaration names. edit: this seems to be incorrect, as Rainer points out in the comment: Scheme actually seems to be a Lisp-1. The following is largely unaffected by this error, though.
Whether a symbol denotes something to be executed or something to be referred to is always clear from the context. Throwing functions and variables into the same namespace is primarily a restriction: the programmer cannot use the same name for a thing and an action. What a Lisp-5 gets out of this is just that some syntactic overhead for referencing something from a different namespace than what the current context implies is avoided. edit: this is not the whole picture, just the surface.
I know that Lisp-5 proponents like the fact that functions are data, and that this is expressed in the language core. I like the fact that I can call a list "list" and a car "car" without confusing my compiler, and functions are a fundamentally special kind of data anyway. edit: this is my main point: separate namespaces are not a wart at all.
I also liked what Pascal Constanza had to say about this.
我在 Python(统一命名空间)与 Ruby(方法与非方法的不同命名空间)中遇到了类似的区别。 在这种情况下,我更喜欢 Python 的方法——例如,使用这种方法,如果我想列出一个事物列表,其中一些是函数,而另一些不是,我不必对它们的名称做任何不同的事情例如,取决于它们的“功能”。 类似的考虑适用于函数对象被四处移动而不是被调用的所有情况(高阶函数的参数和返回值等)。
非函数也可以被调用(如果它们的类定义了
__call__
,在Python的情况下——“运算符重载”的特殊情况),所以“上下文区别”不一定很清楚,任何一个。然而,我的“lisp-oid”经验主要是使用Scheme而不是Common Lisp,所以我可能会潜意识地对最终来自于该经验的统一命名空间的熟悉产生偏见。
I've met a similar distinction in Python (unified namespace) vs Ruby (distinct namespaces for methods vs non-methods). In that context, I prefer Python's approach -- for example, with that approach, if I want to make a list of things, some of which are functions while others aren't, I don't have to do anything different with their names, depending on their "function-ness", for example. Similar considerations apply to all cases in which function objects are to be bandied around rather than called (arguments to, and return values from, higher-order functions, etc, etc).
Non-functions can be called, too (if their classes define
__call__
, in the case of Python -- a special case of "operator overloading") so the "contextual distinction" isn't necessarily clear, either.However, my "lisp-oid" experience is/was mostly with Scheme rather than Common Lisp, so I may be subconsciously biased by the familiarity with the uniform namespace that in the end comes from that experience.
在Scheme中函数的名称只是一个以函数作为其值的变量。 无论我是
(define x (y) (zy))
还是(let ((x (lambda (y) (zy))))
,我都定义了一个因此,就Scheme 而言,“变量名很少出现在那里”的想法有点似是而非。Scheme是一种典型的函数式语言,因此将函数视为数据是其原则之一。让函数成为一种自己的类型,像所有其他数据一样存储是实现这一想法的一种方式。
The name of a function in Scheme is just a variable with the function as its value. Whether I do
(define x (y) (z y))
or(let ((x (lambda (y) (z y))))
, I'm defining a function that I can call. So the idea that "a variable name would rarely want to appear there" is kind of specious as far as Scheme is concerned.Scheme is a characteristically functional language, so treating functions as data is one of its tenets. Having functions be a type of their own that's stored like all other data is a way of carrying on the idea.
我认为,至少对于 Common Lisp 来说,最大的缺点是可理解性。 我们都同意它对变量和函数使用不同的命名空间,但是它有多少个? 在 PAIP 中,Norvig 表明它有“至少七个”命名空间。
当由一位备受尊敬的程序员撰写的该语言的经典书籍之一甚至无法在已出版的书中做出肯定的说明时,我认为存在问题。 我对多个命名空间没有问题,但我希望该语言至少足够简单,以至于某人可以完全理解它的这方面。
我很乐意对变量和函数使用相同的符号,但在更晦涩的区域,我出于恐惧而使用不同的名称(冲突的命名空间可能真的很难调试!),这真的不应该是案件。
The biggest downside I see, at least for Common Lisp, is understandability. We can all agree that it uses different namespaces for variables and functions, but how many does it have? In PAIP, Norvig showed that it has "at least seven" namespaces.
When one of the language's classic books, written by a highly respected programmer, can't even say for certain in a published book, I think there's a problem. I don't have a problem with multiple namespaces, but I wish the language was, at the least, simple enough that somebody could understand this aspect of it entirely.
I'm comfortable using the same symbol for a variable and for a function, but in the more obscure areas I resort to using different names out of fear (colliding namespaces can be really hard to debug!), and that really should never be the case.
这两种方法都有好处。 然而,我发现,在重要的时候,我更喜欢同时拥有一个函数 LIST 和一个变量 LIST,而不是必须拼写错误其中之一。
There's good things to both approaches. However, I find that when it matters, I prefer having both a function LIST and a a variable LIST than having to spell one of them incorrectly.