3

I was preparing for a test and I noticed this question:

Define an object x so that (eq? (car x) (cdr x)) returns #t

I initially thought that it would be pretty simple. cdr x is a list and car x is a single element, so my guess would've been make the first element in x be a list equal to the tail of x. So I came up with

(define x (list (list 1) 1))

Calling car x in DrRacket results in (list 1) and so does cdr x, but when I try to call (eq? (car x) (cdr x)) the result is #f.

What exactly am I missing? Also what would the correct answer be?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Xzenon
  • 1,193
  • 2
  • 15
  • 37

3 Answers3

7

The thing that we can get the car and cdr of is not a list. It is a pair.

Pairs are created with the use of cons, e.g.:

(define val (list 1))

(define val-pair (cons val val))

(list (list 1) 1), on the other hand, is equivalent to (cons (list 1) (list 1)), where list is called twice, each time returning a new, separate object in memory, though holding equal values. But eq? returns true only for the same memory object.

So while your thinking was sound, value-wise, what was actually compared here is not values but the sameness, as in "pointer equality" for memory objects, kind of.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
4

To use your example of using (list 1):

(define x
  (let ([tail (list 1)])
    (cons tail tail)))

An even simpler example:

(define x '(()))    ; same as: (define x (cons (list) (list)))

This relies on the fact that there's only one empty list object (that is, while (eq? (list 1) (list 1)) is always false, (eq? (list) (list)) is always true).


On a related note (though somewhat over the top as far as your test goes), did you know you can also make an object x such that (car x) and (cdr x) refer to the same object as x?

(define x (call-with-input-string "#0=(#0# . #0#)" read))

:-P

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
4

The question is why

(define x (list (list 1) 1))
(eq? (car x) (cdr x))

gives the result #f.

First let's use cons instead of list.

(list 1)    is the same as  (cons 1 '())
(list a b)  is the same as  (cons a (cons b '())

Your example becomes:

(define x (cons (cons 1 '()) 
                (cons 1 '()))
(eq? (car x) (cdr x))

Since we have the expression (cons 1 '()) twice above let's add an index (just so we can refer to the expressions.

(define x (cons (cons_1 1 '()) 
                (cons_2 1 '()))
(eq? (car x) (cdr x))

This shows that

(car x) returns the result of (cons_1 1 '())
(cdr x) returns the result of (cons_2 1 '())

A call (cons a b) will allocate a small data structure in memory that (roughly) looks like this:

<tag-for-pairs>  <pointer-to-the-value-a> <pointer-to-the-value-b>

This means that the calls (cons_1 1 '()) and (cons_2 1 '()) will allocate two pairs each pair will have its own location (address) in memory.

A call (eq? x y) will only compare the location (address) of the two objects x and y. This implied that even though the contents of two pairs are equal, the comparison (eq? (cons_1 1 '()) (cons_2 1 '())) will return false.

soegaard
  • 30,661
  • 4
  • 57
  • 106