1

我对方案中 '(()) 和 (cons null null) 之间的区别感到困惑。

下面的代码表明了这一点,b并且c是完全一样的。

(define (dup2 x)
  (let ((d '(())))
    (set-car! d (car x))
    (set-cdr! d (cdr x))
    d))

(define a '(1 2))

(define b (dup2 a))
(define c (dup2 a))

(set-car! b 2)

> c  ;; --> (2 2)

但是,当我使用dup而不是dup2

(define (dup x)
  (let ((d (cons null null)))
    (set-car! d (car x))
    (set-cdr! d (cdr x))
    d))

(define a '(1 2))

(define b (dup a))
(define c (dup a))

(set-car! b 2)

> c  ;; --> (1 2)

变量bc不同。我做了一些实验,但我还不明白。

4

3 回答 3

1

在第一个实现中的值d是文字数据,并且被修改了未定义的结果。要突出显示正在发生的事情,请考虑以下代码:

(define (incorrect-list-null-and-x x)
  (let ((l '(())))                 ; a list of the form (() . ())
    (set-cdr! l (cons x (cdr l)))  ; (cdr l) is (), so (cons x (cdr l)) should be (x . ()) == (x), right?
                                   ; and now l should be (() . (x . ())) == (() x), right?
    l))

预期的结果是(incorrect-list-null-and-x n)应该返回一个表单列表(() n),并且它是第一次,但是连续的调用仍然访问相同的数据:

(incorrect-list-null-and-x 1) ;=> (() 1)
(incorrect-list-null-and-x 2) ;=> (() 2 1)
(incorrect-list-null-and-x 3) ;=> (() 3 2 1)
(incorrect-list-null-and-x 4) ;=> (() 4 3 2 1)

同样的问题在您的dup2. 从返回的每个值dup2实际上是同一对:

(let* ((x (dup2 (cons 1 2)))
       (y (dup2 (cons 3 4))))
  (display x)
  (display y))

输出:

(3 . 4)(3 . 4)

因为该调用(dup2 (cons 3 4))修改了先前由 . 返回的相同结构(dup2 (cons 1 2))

于 2013-10-03T15:26:34.210 回答
0

像 一样的数据字面量'(())是只读的,并且使用set-car!set-cdr!具有未定义的行为对其进行修改。对于可预测的行为,(cons '() '())如果您想使用set-car!set-cdr!使用它,请使用该版本。

特别是,cons创建一个新的 cons 单元格,而数据文字通常不会。

尽管如此,为了实现的目的,你dup为什么使用set-car!and set-cdr!?直接使用cons即可:

 (define (dup x)
   (cons (car x) (cdr x)))
于 2013-10-03T14:02:20.737 回答
0

在您使用的第一个代码片段(d '(()))中,最终将文字绑定到d. 然后,您修改通常未定义的文字。在您的第二个代码片段中,您使用(d (cons null null))绑定d到新创建的“cons cell”,然后您对其进行修改。修改它没有问题。

注意:您尚未定义null. 也许你的意思是'()?

于 2013-10-03T14:03:38.430 回答