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