题
我来自命令式背景
我读 这里 关于 cons
那
(cons x l):
给定一个LISP对象X和一个列表L,评估(cons x l)创建一个包含X的列表,其后是L。
当我故意不使用列表作为第二个参数时,即
(cons 'a 'a)
我期待一个错误,但哇!我有 (A . A)
.
我错过了什么,什么是 (A . A)
?
解决方案
Cons
构建一个“ Cons Cell”。首先,这与列表无关。一个cons单元是两个值。缺点单元以“虚线对”为书面形式表示,例如 (A . B)
, ,有两个值 'A
和 'B
.
缺席单元中的两个地方称为“汽车”和“ CDR”。您可以将这种缺陷单元视为一个二选块:
car cdr
+-----+-----+
| A | B |
+-----+-----+
在LISP中,值也可以是对其他事物的引用,例如另一个缺点细胞:
+-----+-----+ +-----+-----+
| A | --------> | B | C |
+-----+-----+ +-----+-----+
这将以“虚线对”形式表示为 (A . (B . C))
. 。您可以这样继续:
+-----+-----+ +-----+-----+ +-----+-----+
| A | --------> | B | --------> | C | D |
+-----+-----+ +-----+-----+ +-----+-----+
这是 (A . (B . (C . D)))
. 。如您所见,在这样的结构中,这些值始终在 car
缺席细胞和 cdr
指向其余结构。一个例外是最后一个值,这是最后一个值 cdr
. 。但是,我们不需要这个例外:有一个特殊的价值 NIL
在LISP中,表示“无”。通过放置 NIL
进入最后一个 cdr
, ,您有方便的前哨价值,并且 全部 您的价值在 car
S:
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
| A | --------> | B | --------> | C | --------> | D | NIL |
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
这就是LISP构建列表的方式。自从 (A . (B . (C . (D . NIL))))
有点笨拙,也可以简单地表示 (A B C D)
. NIL
也称为空列表 ()
;这些是同一件事的交换符号。
现在您可以看到为什么 (cons x list)
返回另一个列表。 Cons
只需用 x
在里面 car
并提及 list
在里面 cdr
:
+-----+-----+
| X | --------> list
+-----+-----+
而如果 list
是 (A B)
, ,它的作用为:
+-----+-----+ +-----+-----+ +-----+-----+
| X | --------> | A | --------> | B | NIL |
+-----+-----+ +-----+-----+ +-----+-----+
所以, (cons x '(a b))
评估 (x a b)
.
列表只是缺点单元的一种非常普遍的用途。实际上,实际上,您还可以从缺点单元格,圆形列表或任何有向图的图形中构造任意树。
其他提示
'a
是一个原子, (A . A)
是一个堕落的列表称为 缺点细胞 或“虚线对”。由于您没有通过列表进行参数 L
在 (cons x L)
你把一个牢房拿回来。
(con x l)
给定的X和L,缺点将带有X作为该单元的汽车和L作为该单元的CDR返回一个新的缺点细胞。
列表是缺席细胞的链接链。
CL-USER 141 > (sdraw '(a b c))
[*|*]--->[*|*]--->[*|*]---> NIL
| | |
v v v
A B C
CL-USER 142 > (sdraw (cons 'foo '(a b c)))
[*|*]--->[*|*]--->[*|*]--->[*|*]---> NIL
| | | |
v v v v
FOO A B C
如果Cons获得两个符号作为参数,则看起来像这样:
CL-USER 143 > (sdraw (cons 'foo 'bar))
[*|*]---> BAR
|
v
FOO