【问题标题】:Testing whether two pairs (cons cells) are the same测试两对(cons 单元格)是否相同
【发布时间】:2012-06-08 18:20:40
【问题描述】:

the Seasoned Schemer pg 150 中的以下函数通过改变每个列表的 cdr 然后检查更改是否影响两者来确定两个列表是否具有相同的身份(即占用相同的内存):

(define same?
 (lambda (c1 c2)
   (let ((t1 (cdr c1))
         (t2 (cdr c2)))
     (set-cdr! c1 1)
     (set-cdr! c2 2)
     (let ((v (= (cdr c1) (cdr c2))))
       (set-cdr! c1 t1)
       (set-cdr! c2 t2)
       v))))

现在,如果我将a_list 定义如下:

(define a_list (list 'a 'b 'c 'd))

并评估

(same? a_list (cdr a_list))

函数返回#f,并且调试器(Racket 博士)确认这两个列表——它们应该共享它们的大部分成员,因为第二个参数是第一个参数的真子集——实际上有不同相同成员的副本。这怎么可能?!

稍微改变一下这个想法:

(set-cdr! (cddr a_list) a_list)

现在a_list 是周期性的。如果我用same? 测试这个函数,它只会在两个参数同相时注册#t,即(same? a_list a_list) 和(same? a_list (cdddr a_list))。

[编辑答案位于已接受帖子评论链的底部]

【问题讨论】:

    标签: scheme the-little-schemer seasoned-schemer


    【解决方案1】:

    same? 函数不检查两个列表是否共享元素。 它检查两对(即两个 cons 单元)是否相同。

    在(define a_list (list 'a 'b 'c 'd)) 你有 4 对。 在(same? a_list (cdr a_list))你检查是否第一个 第二对是同一对,因为它们不是, same? 返回#f。

    关于:

    .. 并且调试器(Dr. Racket)确认这两个列表—— 应该分享他们的大部分成员,因为第二个论点是 第一个的真子集——实际上确实有不同的副本 相同的成员。这怎么可能?!

    您能否更准确地了解您如何在 DrRacket 中检查这一点?

    这两个列表 a-list 和 (cdr a-list) 共享成员。

    编辑:

    假设 c1 和 c2 是两个不同的 cons 单元格的名称:

    c1: (foo . bar)      c2:  (baz . qux)
    

    现在我们评估(set-cdr! c1 1) 并得到:

    c1: (foo . 1)      c2:  (baz . qux)
    

    现在我们评估(set-cdr! c2 2) 并得到:

    c1: (foo . 1)      c2:  (baz . 2)
    

    然后我们将cdrs 与(= (cdr c1) (cdr c2)) 进行比较。 由于cdrs 不同,我们得到#f。

    结论:当cons单元不同时,相同吗?返回#f。


    现在假设 c1 和 c2 是同一个 cons 单元格的名称:

    c1 = c2: (foo . bar)
    

    现在我们评估(set-cdr! c1 1) 并得到:

    c1 = c2: (foo . 1)  
    

    现在我们评估(set-cdr! c2 2) 并得到:

    c1 = c2: (foo . 2)  
    

    然后我们将cdrs 与(= (cdr c1) (cdr c2)) 进行比较。 由于cdrs 相同,我们得到#t。

    结论:当cons单元格相同时,same?返回#f。

    编辑 2

    检查 cons 单元格 c 是否是其中之一 l 的缺点单元格使用这个:

    (define (loop c l)
      (cond
        [(null? l) #f]
        [(same? c l) #t]
        [else (loop c (cdr l))]))
    

    【讨论】:

    • 它检查两对(即两个 cons 单元)是否相同。 same? 声称表明两对占用相同的内存,但不清楚对我来说,算法如何区分相同的对和共享一个成员的对。 您能否更准确地了解如何在 DrRacket 中检查这一点?我正在使用 R5RS 中的调试器逐步执行代码
    • @Planarian (A . (B C D)) != (B . (C D)) 这是same? 检查的唯一 项。它不关心在内部那些cdr列表中寻找结构的共享。
    • 顺便说一句 - 通常会使用 eq? 来检查两个 cons 单元格是否相同。
    • @WillNess 我的帖子不质疑same? 是否有效(显然有效),而是为什么。 (set-cdr! (A . (B C D)) 1)怎么对(B . (C D))没有任何影响?
    • @Planarian 因为(B C D) 通过指针 保存在那里,而不是作为内联值。在 Lisp 中,对所有内容都有一个额外的间接级别。 cons 单元格包含两个指向值的指针,而不是两个值。这就是为什么如果重置c2.cdr 中的指针也会重置c1.cdr 中的指针,这意味着c1 和c2 是相同的。
    猜你喜欢
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-24
    • 2016-02-26
    相关资源
    最近更新 更多