Вопрос

The following function from pg 150 of the Seasoned Schemer establishes whether two lists have the same identity (i.e. occupy the same memory) by mutating each list's cdr and then checking whether the change has affected both:

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

Now if I define a_list as follows:

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

and evaluate

(same? a_list (cdr a_list))

the function returns #f, and the debugger (Dr. Racket) confirms that these two lists -- which ought to share most of their members since the second argument is a proper subset of the first -- do in fact have different copies of the same members. How is this possible?!

For a slight twist on this idea:

(set-cdr! (cddr a_list) a_list)

Now a_list is cyclical. If I test this function with same? it only registers #t when the two arguments are in phase, i.e. (same? a_list a_list) and (same? a_list (cdddr a_list)).

[EDIT The answer is at the bottom of the accepted post's comment chain]

Это было полезно?

Решение

The same? function does not check whether two lists share elements. It checks whether two pairs (i.e. two cons cells) are the same.

In (define a_list (list 'a 'b 'c 'd)) you have 4 pairs. In (same? a_list (cdr a_list)) you check whether the first and second pair is the same pair, and since they aren't, same? returns #f.

With respect to:

.. and the debugger (Dr. Racket) confirms that these two lists -- which ought to share most of their members since the second argument is a proper subset of the first -- do in fact have different copies of the same members. How is this possible?!

Can you be more precise about how you check this in DrRacket?

The two lists a-list and (cdr a-list) do share members.

EDIT:

Suppose c1 and c2 are names for two different cons cells:

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

Now we evaluate (set-cdr! c1 1) and get:

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

Now we evaluate (set-cdr! c2 2) and get:

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

Then we compare the cdrs with (= (cdr c1) (cdr c2)). Since the cdrs are different, we get #f.

Conclusion: When the cons cells are different, same? returns #f.


Now suppose c1 and c2 are names for the same cons cell:

c1 = c2: (foo . bar)

Now we evaluate (set-cdr! c1 1) and get:

c1 = c2: (foo . 1)  

Now we evaluate (set-cdr! c2 2) and get:

c1 = c2: (foo . 2)  

Then we compare the cdrs with (= (cdr c1) (cdr c2)). Since the cdrs are the same, we get #t.

Conclusion: When the cons cells are the same, same? returns #f.

EDIT 2

To check whether the cons cell c is one of the cons cells of l use this:

(define (loop c l)
  (cond
    [(null? l) #f]
    [(same? c l) #t]
    [else (loop c (cdr l))]))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top