How eq? in missile work?

At my university, we had to work with Racket, and since I liked it, I bought the recently published book "Realm Of Racket" from No Starch.

However, I cannot understand what they mean in chapter 4 when they try to explain how the equation works:
  • First they explain how equal they are? compares whether two values ​​consist of identical parts. Ok, no problem, I got this: equal? does pretty much the same thing as Java equals (someObject). If two objects / structs / whatever are identical in content, #t is returned.
  • Then, I understand, eq? It should be equivalent to the Java == operator, which is not compared with the content, but based on links.
  • This idea, apparently, is confirmed by the following sentence in the book: "Eq? Compares whether one structure changes the structure of another structure ..." Great! Let's compare it with the following piece of Java code:

    Point p1 = new Point(5, 5); Point p2 = p1; System.out.println(p1 == p2); // true, since the reference has been copied. System.out.println(p1.x); // 5 System.out.println(p2.x); // 5 p1.x = 42; System.out.println(p1.x); // 42 System.out.println(p2.x); // Accordingly, 42 

    Try this on Racket:

     (define cons1 (cons 1 empty)) (define cons2 cons1) (eq? cons1 cons2) ;; #t, since the refernce has been copied. (set! cons1 (cons 2 empty)) cons1 ;; Returns '(2) - as expected. cons2 ;; Still returns '(1). 

    Why? cons2 points to cons1, which itself points to "(2). Besides, didn’t they just say that they are equal as soon as one changes the other?

Obviously, right now I do not understand why this does not behave as expected, and because of this I do not see what eq is? done. Maybe I'm wrong, and this has nothing to do with links ...

If anyone knows about this, please share your wisdom;)

+7
lisp scheme racket
source share
3 answers

For a technical explanation of how eq? works eq? , take a look at the current specification , you will not find a more detailed link, Or just check the Racket documentation on this subject, in particular the eq? procedure eq? eqv? and equal? . As for your question - the result will be the same expected and correct in the code of the Scheme, let's see why. Note that in this line in Java:

 p1.x = 42; 

You are modifying the same object that both p1 and p2 point to. If in this line:

 (set! cons1 (cons 2 empty)) 

You create a new, different object and set cons1 to point to it, but cons2 still points to the old object. You can confirm this, after the previous line, comparison (eq? cons1 cons2) will return #f .

The fact is that the examples are not equivalent. A Java example refers to a single object that is referenced by two different links, while a sample example considers two objects and two links.

For comparison, here is an example of a scheme similar to Java code, and it works as you expected, because here we modify one mutable object that is referenced by two links:

 #lang racket (require scheme/mpair) ;; `m` stands for "mutable" (define p1 (mlist 5 5)) (define p2 p1) (eq? p1 p2) ;; #t (mcar p1) ;; 5 (mcar p2) ;; 5 (set-mcar! p1 42) (eq? p1 p2) ;; #t (mcar p1) ;; 42 (mcar p2) ;; 42 
+7
source share

A: you want to make sure that you are changing the structure. In your example, it does not actually change the structure of the existing value, but rather builds a completely new value and sends it cons1 . Do you have the right concept: eq? - this is pretty much Java == .

Just for the sake of analogy, here the error in the Java form is just so that you see what went wrong:

 int[] lst1 = new int[] { 1 }; // (define cons1 (cons 1 empty)) int[] lst2 = lst1; // (define cons2 cons1) System.out.println(lst1 == lst2); // (eq? cons1 cons2) lst1 = new int[] { 2 }; // (set! cons1 (cons 2 empty)) System.out.println(lst1[0]); // (list-ref cons1 0) System.out.println(lst2[0]); // (list-ref cons2 0) 

In fact, at this point you will want to check eq? -ness at the end of this: will you see that they are no longer eq? : these are two different meanings.

What you really want is to make a mutation in the structure, not a variable. In Racket, since lists are immutable, you will want to use a different data structure that allows mutation. Vectors are one example of a data type that can demonstrate. Let Rosetta again, so you see the analogy:

 (define vec1 (vector 1)) ;; int[] vec1 = new int[] { 1 }; (define vec2 vec1) ;; int[] vec2 = vec1; (eq? vec1 vec2) ;; System.out.println(vec1 == vec2); (vector-set! vec1 0 2) ;; vec1[0] = 2; (vector-ref vec1 0) ;; System.out.println(vec1[0]); (vector-ref vec2 0) ;; System.out.println(vec2[0]); 
+3
source share

Are you right that eq? compares links to determine equality. Is it much more efficient than equal? , which should recursively compare objects.

Does the Racket documentation explicitly define each, as well as its associated eqv? function eqv? :

<b> are equal?

Are two values ​​equal? if and only if they are eqv ?, unless otherwise indicated for a particular data type.

Data types with an extra specification of equal? include strings, byte strings, pairs, mutable pairs, vectors, fields, hash tables, and structures to check. In the last six cases, equality is recursively determined; if both v1 and v2 contain reference loops, they are equal when infinite sweeps of values ​​are equal.

Examples:

 > (equal? 'yes 'yes) #t > (equal? 'yes 'no) #f > (equal? (expt 2 100) (expt 2 100)) #t > (equal? 2 2.0) #f > (equal? (make-string 3 #\z) (make-string 3 #\z)) #t 

eq?

Two values: eqv? if and only if they are eq ?, unless otherwise indicated for a particular data type.

The number and characteristic data types are the only ones for which eqv? different from eq ?.

Examples:

 > (eqv? 'yes 'yes) #t > (eqv? 'yes 'no) #f > (eqv? (expt 2 100) (expt 2 100)) #t > (eqv? 2 2.0) #f > (eqv? (integer->char 955) (integer->char 955)) #t > (eqv? (make-string 3 #\z) (make-string 3 #\z)) #f 

eq?

Returns #t if v1 and v2 refer to the same object, #f otherwise.

Examples:

 > (eq? 'yes 'yes) #t > (eq? 'yes 'no) #f > (let ([v (mcons 1 2)]) (eq? vv)) #t > (eq? (mcons 1 2) (mcons 1 2)) #f > (eq? (make-string 3 #\z) (make-string 3 #\z)) #f 
+2
source share

All Articles