怎么"缺点"在Lisp工作?

时间:2015-04-17 15:32:16

标签: lisp common-lisp cons

我正在学习Lisp,我对Lisp编程没有经验。在我的部分学习中,我遇到了以下例子:

> (cons ‘a ‘(a b))  ----> (A A B)
> (cons ‘(a b) ‘a)  ----> ((A B).A)

我想知道为什么当我们(cons'a'(ab))时,响应是(AAB)以及为什么当我们稍微更改它并放入在(ab)之后' a ,响应是一个虚线列表,如((AB).A)?第一个代码行和第二个代码行有什么区别?这些代码背后发生了什么?

4 个答案:

答案 0 :(得分:12)

如果您将它们视为cons-cells,则很容易理解。

简而言之,cons单元格由完全两个值组成。通常的表示法是使用点,例如:

(cons 'a 'b) ==> (A . B)

但是由于列表在LISP中经常使用,因此更好的方法是删除点。 通过使第二个元素成为新的cons单元格来制作列表,最后一个结尾是终止符(通常为nil,或Common Lisp中的'())。所以这两者是平等的:

(cons 'a (cons 'b '())) ==> (A B)
(list 'a 'b) ==> (A B)

因此(cons 'a 'b)会创建一个单元格[a,b],而(list 'a 'b)会创建[a, [b, nil]]。请注意在cons单元格中编码列表的约定:它们以内部nil终止。

现在,如果您将'a放在最后一个列表中,则会创建一个包含[[a, [b, nil]], a]的新增长单元格。因为这不是一个适当的"列表,即它没有以nil结尾,写出来的方法是使用点:(cons '(a b) 'a) ==> ((a b) . a)

如果没有打印点,则必须是具有结构[[a, [b, nil]], [a, nil]]的列表。

您的示例

当您执行(cons 'a '(a b))时,它将采用符号'a和列表'(a b)并将它们放入新的增量单元格中。所以这将由[a, [a, [b, nil]]]组成。因为这自然以内部nil结束,所以它没有点。

至于(cons '(a b) 'a),现在您将获得[[a, [b, nil]], a]以内部nil终止,因此将使用点表示法。

我们可以使用cons来使最后一个示例以内部nil结尾吗?是的,如果我们这样做

(cons '(a b) (cons 'a '())) ==> ((A B) A)

最后,

(list '(a b) 'a))

相当于

(cons (cons (cons 'a (cons 'b '())) (cons 'a '())))

答案 1 :(得分:6)

请参阅此可视化:

CL-USER 7 > (sdraw:sdraw '(A A B))

[*|*]--->[*|*]--->[*|*]--->NIL
 |        |        |
 v        v        v
 A        A        B

CL-USER 8 > (sdraw:sdraw '((A B) . A))

[*|*]--->A
 |
 v
[*|*]--->[*|*]--->NIL
 |        |
 v        v
 A        B

此外:

CL-USER 9 > (sdraw:sdraw '(A B))

[*|*]--->[*|*]--->NIL
 |        |
 v        v
 A        B

CL-USER 10 > (sdraw:sdraw (cons 'A '(A B)))

[*|*]--->[*|*]--->[*|*]--->NIL
 |        |        |
 v        v        v
 A        A        B

CL-USER 11 > (sdraw:sdraw (cons '(A B) 'A))

[*|*]--->A
 |
 v
[*|*]--->[*|*]--->NIL
 |        |
 v        v
 A        B

答案 2 :(得分:3)

列表(a b c)表示为(内部存储)三个cons-cells:(cons 'a (cons 'b (cons 'c '())。请注意,最后一对在其cdr中有'()。

打印机将最后一个cdr为'()的系列单元打印为列表。因此,该例子印刷为(a b c)。

让我们来看看:(cons 'a '(a b))

列表'(a b)表示为(cons'a(cons'b'())。这意味着 (cons 'a '(a b))生成:(cons 'a (cons 'a (cons 'b '()))

我们来看看:(cons '(a b) 'a)

列表'(a b)表示为(cons'a(cons'b'())。这意味着 (cons (cons '(a b) 'a))生成(cons (cons 'a (cons 'b '()) 'a)

请注意,此系列不会以'()结尾。显示打印机使用点表示法。 ( ... . 'a)表示值由一系列cons-cells组成,最后一个cdr包含'a。因此,值(cons (cons 'a (cons 'b '()) 'a)将打印为'((a b) . a)

答案 3 :(得分:2)

cons是一个可以包含两个值的数据结构。例如(cons 1 2) ; ==> (1 . 2)。第一部分是car,第二部分是cdr。如果cons listcdrnil,则list(1 . (2 . (3 . ())))。从而  cons是一个列表。

打印cdr时,如果consnilcdr,则会忽略该点。 (3 . ())的外括号也被省略。因此(3)打印(1 . (2 . (3 . ())))(1 2 3)打印cons。它具有相同的结构,但具有不同的可视化。 car中的cons没有此规则。

cdr是列表时,read函数用点读取cons和奇怪的异常打印格式。它在读取时的行为就像是read

对于printcons都有一个特殊规则,即使列表(cons ‘a ‘(a b)) ----> (A . (A B)) (cons ‘(a b) ‘a) ----> ((A B) . A) 链接,列表的幻觉也会完整。

cdr

打印时,第一个是3个元素的列表,因为{{1}}是一个列表。