`(mcons (mcons '() 25) 16)` 和 `(mcons 25 (mcons 16 `()))` 有什么区别

What is the difference between `(mcons (mcons '() 25) 16)` and `(mcons 25 (mcons 16 `()))`

我在忙Structure and Interpretation of Computer Programs exercise 2.18。这里我们必须定义一个过程 reverse 来反转列表。它应该执行以下操作:

(reverse (list 1 4 9 16 25))
;; => (25 16 9 4 1)

我想出了以下定义:

(define (reverse list)
  (if (null? list) 
      list
      (cons (reverse (cdr list)) (car list))))
;; => (mcons (mcons (mcons (mcons (mcons '() 25) 16) 9) 4) 1).

然后在a solution中发现了类似如下的内容:

(define (reverse items) 
  (if (null? (cdr items)) 
      items 
      (append (reverse (cdr items)) 
              (cons (car items) nil))))
;; => (mcons 25 (mcons 16 (mcons 9 (mcons 4 (mcons 1 '()))))).

appendcons 之间的区别在这里我无法指出。

我的问题:有什么区别,为什么结果不显示为 (25 16 9 4 1)

简短回答:reverse 的第一个版本错误地构建了一个 不正确的 列表,第二个版本低效地构建了一个 正确的 [=49] =] 列表。只要弄清楚appendcons.

的区别,我们就能做得更好

append 连接两个 列表 。如果我们只用它在一个列表的末尾添加一个元素,我们将做比需要更多的工作:我们将不得不遍历整个列表每次只是为了放置最后一个元素(参见:Schlemiel the Painter's algorithm)。因此,使用 appendreverse 实现在复杂性上可能与 O(n^2) 一样糟糕。

另一方面,cons 将单个元素添加到列表的头部,因为 reverse 的实现复杂度 O(n)。一般来说,在 Scheme 中你应该尽量避免使用 append 来构建一个新的输出列表,总是首选 cons。现在让我们看看你的算法使用 cons:

返回了什么
(reverse '(1 2 3 4 5))
=> '(((((() . 5) . 4) . 3) . 2) . 1)

这是为什么?因为要用 cons 构建一个正确的列表,第二个参数必须是另一个正确的列表,但是你传递的是一个元素。正确的实现需要一个累加器参数——顺便说一句,这样效率更高,因为它使用了尾递归,这个概念你应该已经很熟悉了,因为它在这本书。试试这个:

(define (reverse lst acc)
  (if (null? lst)
      acc
      (reverse (cdr lst) (cons (car lst) acc))))

(reverse '(1 2 3 4 5) '())
=> '(5 4 3 2 1)

对于问题的最后一部分:列表显示为 mconsm 表示 cons 单元格 可变 ) 由于您使用的语言,请尝试切换到 #lang racket,它默认使用 immutable cons 单元格,并将按您的预期打印.