【问题标题】:Unexpected output with cons()带有 cons() 的意外输出
【发布时间】:2011-03-29 18:47:19
【问题描述】:

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

我读到here 提到了cons

(缺点 x L):

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

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

(cons 'a 'a) 我预计会出错,但哇!我得到了(A . A)

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

【问题讨论】:

    标签: lisp common-lisp cons


    【解决方案1】:

    Cons 构造一个“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,您就有了一个方便的标记值,并且所有您的值都在cars 中:

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

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

    现在您可以看到为什么(cons x list) 返回另一个列表了。 Cons 只是在car 中使用x 和在cdr 中对list 的引用构造另一个cons 单元格:

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

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

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

    所以,(cons x '(a b)) 的计算结果为 (x a b)

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

    【讨论】:

      【解决方案2】:

      (CONS 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
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 2022-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多