Lisp 与x27之间的差异;(())和(cons null)

Lisp 与x27之间的差异;(())和(cons null),lisp,scheme,Lisp,Scheme,我对scheme中的“(())和(cons 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)

我对scheme中的“(())和(cons 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)

变量
b
c
是不同的。我做了一些实验,但我还不明白。

数据文本,如
'(())
,应该是只读的,并使用
set car修改它
设置cdr具有未定义的行为。对于可预测的行为,如果要使用
设置汽车,请使用
(cons'()'())
版本
设置cdr在上面

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

不过,为了实现
dup
,为什么要使用
set car
设置cdr无论如何?直接使用
cons

 (define (dup x)
   (cons (car x) (cdr x)))

数据文本,如
”(())
,是只读的,可以使用
set car修改它
设置cdr具有未定义的行为。对于可预测的行为,如果要使用
设置汽车,请使用
(cons'()'())
版本
设置cdr在上面

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

不过,为了实现
dup
,为什么要使用
set car
设置cdr无论如何?直接使用
cons

 (define (dup x)
   (cons (car x) (cdr x)))

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


注意:您尚未定义
null
。也许您的意思是“()?

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


注意:您尚未定义
null
。也许您的意思是“()?

在第一个实现中,
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))
预期的结果是
(不正确的-list-null-and-x n)
应该返回一个形式为
(()n)
的列表,并且它是第一次返回,但连续调用仍在访问相同的数据:

同样的问题在您的
dup2
中表现得有点不同。从
dup2
返回的每个值实际上都是同一对:

产出:

(3 . 4)(3 . 4)

因为调用
(dup2(cons 3 4))
修改了先前由
(dup2(cons 1 2))
返回的相同结构,所以第一个实现中
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))
预期的结果是
(不正确的-list-null-and-x n)
应该返回一个形式为
(()n)
的列表,并且它是第一次返回,但连续调用仍在访问相同的数据:

同样的问题在您的
dup2
中表现得有点不同。从
dup2
返回的每个值实际上都是同一对:

产出:

(3 . 4)(3 . 4)

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

null在scheme中被定义为“()”,编辑:仅在某些实现中更正感谢
(define null'null)
不是一个好的假设。OP显然打算
(())
(cons null null)
@DanielV在某些实现中是相等的。在Scheme标准中没有定义它。在Scheme中null定义为“()编辑:仅在某些实现中更正,这要感谢
(定义null'null)
不是一个好的假设。OP显然打算
(())
(cons null null)
@DanielV在某些实现中是相等的。方案标准中未定义。可能重复。问题在于引用的数据,而不是
'(())
(cons null null)
的值存在差异。尝试将
(())
替换为
(list'())
,您将不再观察到此问题。(重复不是Scheme,而是Common Lisp,但问题是相同的。)为了获得更多乐趣,与其做一个
dup
过程,不如尝试编写一个将数据推入列表
d
,您会看到列表在多次调用中变得越来越长。的可能重复。问题在于引用的数据,而不是
'(())
(cons null null)
的值存在差异。尝试将
(())
替换为
(list'())
,您将不再观察到此问题。(这个重复不是Scheme,而是Common Lisp,但问题是相同的。)为了获得更多的乐趣,与其做一个
dup
过程,不如尝试编写一个将数据推送到列表
d
中的过程,您会看到列表在多次调用中越来越长。