Racket has more than one function for testing the equality of two items. Why? So that specialized equality functions can be optimized to run faster. But if you’re not comparing data types that are appropriate, you’ll get inaccurate results. Choose with care.
equal? gives the right answer for all data types, though it’s the slowest of the equality functions. When in doubt, use this. It diligently inspects every value, including values enclosed in two lists:
1 2 3 4 | (equal? "foobar" (string-append "foo" "bar")) ; #t (equal? '(1 2 3 4) (append '(1 2) '(3 4))) ; #t (equal? 42 (* 6 7)) ; #t (equal? 'symbol (string->symbol "symbol")) ; #t |
eq? is mostly restricted to symbols, small integers (called fixnums), and objects. eq? can be much faster than equal? because it doesn’t actually inspect the values of the two items. Rather, it simply checks if the items refer to the same chunk of memory. (Those familiar with memory operations might know this as pointer comparison.)
1 2 3 4 | (eq? "foobar" (string-append "foo" "bar")) ; #f (eq? '(1 2 3 4) (append '(1 2) '(3 4))) ; #f (eq? 42 (* 6 7)) ; #t (eq? 'symbol (string->symbol "symbol")) ; #t |
Its reliance on pointer comparison, however, is why eq? is limited to symbols and a handful of other data types that are interned. Conversely, it’s also why you’ll see symbols chosen for situations where speedy comparisons are needed, because then you can use eq?.
Take extra care with eq?, which can lead newcomers astray with its ability to give seemingly accurate results in simple test cases (like numbers and strings), then seemingly fail when the input gets more complex. In those cases, eq? is right; your expectations are wrong.
eqv? is like eq?, but handles characters and all numbers consistently.
= is like eqv?, but limited to numbers, and can be faster than equal?.
Stringlike types explainer
Numbers explainer
Equality in the Racket Reference