Lisp中的空列表是从cons单元格生成的吗?

Lisp中的空列表是从cons单元格生成的吗?,lisp,null,cons,Lisp,Null,Cons,我试图在JavaScript中模拟类似Lisp的列表(只是一个没有实际原因的练习),但我正在努力找出如何最好地表示空列表 空列表只是一个nil值,还是存储在cons单元格中 我可以: (car '()) NIL (cdr '()) NIL 但是空列表肯定不能是(cons nil nil),因为它与存储单个nil的列表无法区分。它需要存储一些其他特殊值 另一方面,如果不是从cons单元格构建空列表,则似乎不可能有一个一致的高级接口,用于向现有列表追加单个值。类似于以下的函数: (defun ap

我试图在JavaScript中模拟类似Lisp的列表(只是一个没有实际原因的练习),但我正在努力找出如何最好地表示空列表

空列表只是一个
nil
值,还是存储在cons单元格中

我可以:

(car '())
NIL
(cdr '())
NIL
但是空列表肯定不能是
(cons nil nil)
,因为它与存储单个
nil
的列表无法区分。它需要存储一些其他特殊值

另一方面,如果不是从cons单元格构建空列表,则似乎不可能有一个一致的高级接口,用于向现有列表追加单个值。类似于以下的函数:

(defun append-value (list value) ...

将修改其参数,但前提是它不是空列表,这看起来很难看。

请使用您的Lisp解释器进行尝试:

(eq nil '())
=> t
在对空列表执行
nil
/操作时,有几个操作是特殊情况,可以执行非正交(甚至是奇怪的:-)操作。您正在调查的
car
cdr
的行为就是其中之一


nil
作为空列表的标识是您了解Lisp的第一件事。我试着在谷歌上找到一个好的点击率,但我只选一个,因为有太多了:

一个空列表就是
nil
符号(根据定义,符号不是conses)<如果给定
nil
,则定义code>car和
cdr
返回
nil

对于列表变异函数,它们返回一个您应该重新分配给变量的值。例如,看看函数的规范:它可能修改给定的列表,也可能不修改,您应该使用返回值,而不是依赖它进行适当的修改


甚至,典型的破坏性追加函数也是这样工作的:它的返回值是您应该使用的追加列表。它被指定在适当的位置修改给定的列表(最后一个除外),但是如果您将它作为第一个参数,它不能很好地修改它,因此您仍然必须使用返回值。

信不信由你,这实际上是一个宗教问题

有些方言人们敢称之为某种Lisp,其中空列表是某种类型的conse或聚合对象,而不仅仅是像
nil
这样的原子

例如,在“MatzLisp”(更好地称为Ruby)中,列表实际上是数组

在NewLisp中,列表是容器:列表类型的对象包含项目的链接列表,所以空列表是空容器

在Lisp语言中,空列表是原子,非空列表是二进制单元格,其中一个字段包含第一项,另一个字段包含列表的其余部分。列表可以共享后缀。给定一个类似
(1 2 3)
的列表,我们可以使用
cons
创建
(a 1 2 3)
(b c 1 2 3)
,这两个列表共享
(1 2 3)
的存储空间

(在ANSI Common Lisp中,空列表atom
()
与符号
nil
是同一个对象,其计算结果为自身,也用作布尔值false。在Scheme中,
()
不是一个符号,它不同于布尔值false
#f
对象。但是,方案列表仍然是成对的,并以原子结尾。)

评估
(car nil)
的能力不会自动遵循列表的cons和nil表示,如果我们查看古老的Lisp文档,例如1960年初的Lisp 1.5手册,我们会发现这是不存在的。最初,
car
严格来说是访问cons单元格字段的一种方式,并且严格要求使用cons单元格参数

像允许
(无车)
正常工作(这样黑客就可以从程序中删除许多无用的代码行)这样的好主意不是一夜之间出现的。允许
(无车)
的想法可能是InterLisp提出的。无论如何,Lisp文件的演变声称MacLisp(Common Lisp的重要前身之一,与二十年后的苹果Macintosh无关)模仿了InterLisp(另一个重要的前身)的这一功能


像这样的小细节决定了愉快编程和对着显示器骂人之间的区别:例如,请看一位Lisp程序员与一种令人愉快的方言的斗争,在这种方言中,空列表无法通过
汽车访问,不要充当布尔值false。

NIL
在公共Lisp中有点奇怪,因为

  • 它是一个符号(意思是
    symbolp
    返回
    T
  • 这是一份清单
  • 不是cons单元格(
    consp
    返回
    NIL
  • 无论如何,您都可以使用
    CAR
    CDR

请注意,这背后的原因可能也是历史原因,您不应该认为这是唯一合理的解决方案。其他Lisp方言做出了不同的选择。

是的,我知道它的身份,但我想知道它的内部表示。因此,就其参数而言,不可能有一个具有一致接口的附加值函数?@JanWrobel正如我在回答中提到的,您的接口应该返回新值,它可能是相同的列表,也可能不是,这取决于您是否能够对其进行适当的修改。不管怎样,调用方都应该使用返回值,必要时重新分配回他们的变量。我编辑了您的帖子以使用
defun
,而不是
define
,它来自Scheme。我不认为你在谈论Scheme,因为Scheme没有
nil
,它不允许你将空列表传递给
car
cdr
,并且在Schem中使用直接列表变异更不受欢迎