我来自一个势在必行的背景,但这些天我在LISP上尝试(普通LISP)
我读了here 关于cons
(cons x L):
给定LISP对象x和列表L,求值(cons x L)创建一个包含x的列表,后跟L中的元素。
当我故意不使用列表作为第二个参数时,即当我使用
时 (cons 'a 'a)
我预计会出错,但哇!我得到了(A . A)
。
我错过了什么,(A . A)
是什么?
答案 0 :(得分:7)
Cons
构建了“利弊细胞”。这与列表最初没有任何关系。 cons单元格是一对两个值。 cons单元以书面形式由“点对”表示,例如, (A . B)
,其中包含两个值'A
和'B
。
cons单元格中的两个位置称为“car”和“cdr”。您可以将这样的cons单元可视化为一个二分块:
car cdr
+-----+-----+
| A | B |
+-----+-----+
在Lisp中,值也可以是对其他内容的引用,例如,另一个cons单元格:
+-----+-----+ +-----+-----+
| A | --------> | B | C |
+-----+-----+ +-----+-----+
这将以“点对”形式表示为(A . (B . C))
。你可以这样继续:
+-----+-----+ +-----+-----+ +-----+-----+
| A | --------> | B | --------> | C | D |
+-----+-----+ +-----+-----+ +-----+-----+
这是(A . (B . (C . D)))
。如您所见,在这样的结构中,值始终位于cons单元格的car
中,而cdr
指向结构的其余部分。最后一个值是最后一个cdr
。但是我们不需要这个例外:Lisp中有一个特殊值NIL
,表示“无”。通过将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)
。
列表只是cons细胞的一种常见用法。您还可以从cons单元格,圆形列表或任何有向图形构造任意树。实际上。
答案 1 :(得分:1)
'a
是一个lisp原子,(A . A)
是一个简并列表,称为cons cell或“点对”。由于您没有在L
中传递参数(cons x L)
的列表,因此您返回了一个单元格。
答案 2 :(得分:1)
(CONS x L)
给定x和L,CONS返回一个新的cons单元格,x为该单元格的CAR,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