What is the difference between eq?, eqv?, equal?, and = in Scheme?

I wonder what the difference is between those operations in Scheme. I have seen similar questions in Stack Overflow but they are about Lisp, and there is not a comparison between three of those operators. I am writing the different types of commands in Scheme, and I get the following outputs:

(eq? 5 5) -->#t (eq? 2.5 2.5) -->#f (equal? 2.5 2.5) --> #t (= 2.5 2.5) --> #t 
Why is this the case? 19.2k 9 9 gold badges 119 119 silver badges 152 152 bronze badges asked Apr 30, 2013 at 11:52 10.7k 34 34 gold badges 103 103 silver badges 169 169 bronze badges and there's also eqv? , which means something different from eq? or equal? Commented May 1, 2013 at 1:59

7 Answers 7

I'll answer this question incrementally. Let's start with the = equivalence predicate. The = predicate is used to check whether two numbers are equal. If you supply it anything else but a number then it will raise an error:

(= 2 3) => #f (= 2.5 2.5) => #t (= '() '()) => error 

The eq? predicate is used to check whether its two parameters respresent the same object in memory. For example:

(define x '(2 3)) (define y '(2 3)) (eq? x y) => #f (define y x) (eq? x y) => #t 

Note however that there's only one empty list '() in memory (actually the empty list doesn't exist in memory, but a pointer to the memory location 0 is considered as the empty list). Hence when comparing empty lists eq? will always return #t (because they represent the same object in memory):

(define x '()) (define y '()) (eq? x y) => #t 

Now depending upon the implementation eq? may or may not return #t for primitive values such as numbers, strings, etc. For example:

(eq? 2 2) => depends upon the implementation (eq? "a" "a") => depends upon the implementation 

This is where the eqv? predicate comes into picture. The eqv? is exactly the same as the eq? predicate, except that it will always return #t for same primitive values. For example:

(eqv? 2 2) => #t (eqv? "a" "a") => depends upon the implementation 

Hence eqv? is a superset of eq? and for most cases you should use eqv? instead of eq? .

Finally we come to the equal? predicate. The equal? predicate is exactly the same as the eqv? predicate, except that it can also be used to test whether two lists, vectors, etc. have corresponding elements which satisfy the eqv? predicate. For example:

(define x '(2 3)) (define y '(2 3)) (equal? x y) => #t (eqv? x y) => #f 
  1. Use the = predicate when you wish to test whether two numbers are equivalent.
  2. Use the eqv? predicate when you wish to test whether two non-numeric values are equivalent.
  3. Use the equal? predicate when you wish to test whether two lists, vectors, etc. are equivalent.
  4. Don't use the eq? predicate unless you know exactly what you're doing.
1,846 18 18 silver badges 21 21 bronze badges answered Jul 18, 2013 at 9:35 Aadit M Shah Aadit M Shah 73.9k 31 31 gold badges 173 173 silver badges 304 304 bronze badges

AFAIK (eqv? "a" "a") ==> unspecified . You'll have to use equal? or (the possibly more optimized) string=?

Commented Jul 18, 2013 at 21:02

according to the Report, (eq? '(1) '(1)) is unspecified, so your (define x '(1 2)) illustration might not work.

Commented Jul 19, 2013 at 7:33 Very accurate and informative. Especially the guidelines at the end. Commented Jul 31, 2015 at 8:17

But eq? seems to be defined for symbols and this should be noted! If the symbols look the same, eq? returns #t. Example (eq? 'foo 'foo) -> #t , (eq? 'foo 'bar) -> false`. I read this here and here

Commented Jul 3, 2016 at 15:47

There are a full two pages in the RnRS specification related to eq?, eqv?, equal? and = . Here is the Draft R7RS Specification. Check it out!

15.6k 4 4 gold badges 60 60 silver badges 77 77 bronze badges answered Apr 30, 2013 at 18:38 69.6k 20 20 gold badges 99 99 silver badges 148 148 bronze badges The link to the Draft R7RS Specification is dead as of 2018-02-04 Commented Feb 4, 2018 at 17:36 Updated to a live link. Commented Feb 5, 2018 at 19:17

The comment about equal? / eqv? on numbers is incorrect in an subtle manner. equal? / eqv? reduces to = if both operands are of the same exactness. So (= 1 1.0) is true while (eqv? 1 1.0) is false.

Commented Nov 9, 2023 at 21:49

eq? is #t when it is the same address/object. Normally one could expect #t for same symbol, boolean and object and #f for values that is of different type, with different values, or not the same structure Scheme/Lisp-implementations has a tradition to embed type in their pointers and to embed values in the same space if it's enough space. Thus some pointers really are not addresses but values, like the char R or the Fixnum 10 . These will be eq? since the "address" is an embedded type+value. Some implementations also reuse immutable constants. (eq? '(1 2 3) '(1 2 3)) might be #f when interpreted but #t when compiled since it might get the same address. (Like the constant String pool in Java). Because of this, many expresions involving eq? are unspecified, thus wether it evaluates to #t or #f is implementation dependent.

eqv? are #t for the same things as eq? . It is also #t if it's a number or character and it's value is the same, even when the data is too big to fit into a pointer. Thus for those eqv? does the extra work of checking that type is one of the supported, that both are the same type and it's target objects have the same data value.

equal? is #t for the same things as eqv? and if it's a compound type like pair, vector, string, and bytevector it recursively does equal? with the parts. In practice it will return #t if the two objects looks the same. Prior to R6RS, it's unsafe to use equal? on circular structures.

= is like eqv? but it only works for numeric types. It might be more efficient.

string=? is like equal? , but it only works for strings. It might be more efficient.