在有载体的lisp中,为什么cons细胞仍然是必要的据我所知,一个cons单元是:
只有两个元素的结构
命令
通道为O(1)
不过,所有这些也适用于2向量。那有什么区别呢cons细胞只是Lisps有载体之前的痕迹吗或者还有其他我不知道的区别吗?
最佳答案
尽管conse在物理上类似于任何其他两元素聚合结构,但它们并不仅仅是2-向量的过时形式。
首先,将Lisp中的所有类型划分为cons
和atom
只有conse是cons
类型的;其他的都是原子矢量就是原子!
conse构成了嵌套列表的表示基础,当然这些列表用于编写代码它们有一个特殊的打印符号,使得由(cons 1 (cons 2 nil))
生成的对象方便地打印为(1 2)
,而由(cons 1 (cons 2 3))
生成的对象打印为(1 2 . 3)
。cons
与atom
的区别在语法中很重要,因为满足consp
测试的表达式被视为复合形式而不是关键字符号的原子,则对它们自己求值。
为了获得列表本身而不是复合表单的值,我们使用了t
,对此我们有一个很好的速记。
有一个向量类型是很有用的,它不会以这种方式纠缠到求值语义中:它的实例只是自求值原子。
Cons细胞不是Lisps有载体之前的痕迹首先,几乎没有这样的时间1960年的Lisp 1手册已经描述了数组其次,自此以后的新方言仍有其特点。
具有相似表示的对象并不是简单地相互冗余的类型区分很重要。例如,我们不会因为以下两个插槽都有三个而认为它们彼此是多余的:
(defstruct name first initial last)
(defstruct bank-transaction account type amount)
在TXR Lisp方言中,我曾经使用过它,因此语法糖
nil
表示范围quote
但这意味着范围是a..b
,这是愚蠢的,因为对列表的模糊性我最终改变了它,使(cons a b)
表示consp
:一种构造范围对象的表单,它打印为a..b
。(也可以指定为文字)这会产生有用的细微差别,因为我们可以区分函数参数是范围((rcons a b)
)还是列表(#R(x y)
)就像我们关心某个对象是rangep
还是consp
。范围对象的表示方式与conse完全相同,并从相同的堆中分配;只是它们有一种不同的类型,使它们成为原子如果以表格的形式进行评估,他们会对自己进行评估。基本上,我们必须把类型当作一个额外的槽两个元素向量实际上(至少)有三个属性,而不仅仅是两个:它有第一个元素、第二个元素和一个类型。向量
bank-transaction
不同于cons cellname
,因为它们都有第三个方面,即类型,这是不同的。一个对象的不可变属性,它与其他同类对象共享,仍然可以被视为“槽”实际上,所有对象都有一个“类型槽”因此conse实际上是三个属性对象,分别具有
#(1 1)
、(1 . 1)
和car
:(car '(a . b)) -> A
(cdr '(a . b)) -> B
(type-of '(a . b)) -> CONS
她是第四个“槽”:
(class-of '(a . b)) -> #<BUILT-IN-CLASS CONS>
我们不能仅仅根据堆上分配的每个实例的存储向量来看待对象。
顺便说一句,20世纪60年代的MacLisp方言将cons的概念扩展到具有更多命名字段的固定大小聚合对象(除了
cdr
和type
):这些对象被称为“hunks”,它们是documented in Kent Pitman's MacLisp manual帅哥不满足于谓词,但他们被认为是原子。然而,他们用多个点扩展了cons符号。关于lisp - con单元格和2向量之间有什么区别?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40261604/