11

我来自命令式背景,但这些天我尝试使用 LISP(Common LISP)

我在这里读到了cons

(cons x L):

给定一个 LISP 对象 x 和一个列表 L,计算 (cons x L) 创建一个包含 x 和 L 中的元素的列表。

当我故意不使用列表作为第二个参数时,即当我使用

(cons 'a 'a)我期待一个错误,但哇!我得到了(A . A)

我错过了什么,什么是 (A . A)

4

3 回答 3

7

Cons构造一个“cons cell”。这最初与列表无关。一个 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))). 如您所见,在这样的结构中,值始终位于carcons 单元格中,并且cdr指向结构的其余部分。一个例外是最后一个值,它位于 last 中cdr。不过,我们不需要这个例外:NIL在 Lisp 中有一个特殊的值,它表示“无”。通过放入NILlast cdr,您有一个方便的哨兵值,并且您的所有值都在cars 中:

+-----+-----+       +-----+-----+       +-----+-----+       +-----+-----+
|  A  |   --------> |  B  |   --------> |  C  |   --------> |  D  | NIL |
+-----+-----+       +-----+-----+       +-----+-----+       +-----+-----+

这就是在 Lisp 中构建列表的方式。由于(A . (B . (C . (D . NIL))))有点笨拙,也可以简单地表示为(A B C D)NIL也称为空列表();这些是同一事物的可交换符号。

现在您可以看到为什么(cons x list)返回另一个列表。 简单地用inCons构造另一个 cons 单元格,并在中引用:xcarlistcdr

+-----+-----+
|  X  |   --------> list
+-----+-----+

如果list(A B),则结果为:

+-----+-----+       +-----+-----+       +-----+-----+
|  X  |   --------> |  A  |   --------> |  B  | NIL |
+-----+-----+       +-----+-----+       +-----+-----+

因此,(cons x '(a b))评估为(x a b)

列表只是 cons 单元格的一种非常常见的用法。实际上,您还可以从 cons 单元格、循环列表或任何有向图构造任意树。

于 2010-08-14T09:34:45.280 回答
1

'a是一个 lisp atom 并且(A . A)是一个退化列表,称为cons 单元或“点对”。由于您没有传递参数列表L,因此(cons x L)您返回了一个单元格。

于 2010-08-14T06:59:46.207 回答
1

(缺点 x L)

给定 x 和 L,CONS 返回一个新的 cons 单元,其中 x 作为该单元的 CAR,L 作为该单元的 CDR。

列表是 cons 单元的链接链。

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
于 2010-08-14T09:31:39.667 回答