Next: Numbers, Previous: Special Forms, Up: Top
A predicate is a procedure that always returns a boolean value
(#t
or #f
). An equivalence predicate is the
computational analogue of a mathematical equivalence relation (it is
symmetric, reflexive, and transitive). Of the equivalence predicates
described in this section, eq?
is the finest or most
discriminating, and equal?
is the coarsest. eqv?
is
slightly less discriminating than eq?
.
The
eqv?
procedure defines a useful equivalence relation on objects. Briefly, it returns#t
if obj1 and obj2 should normally be regarded as the same object.The
eqv?
procedure returns#t
if:
- obj1 and obj2 are both
#t
or both#f
.- obj1 and obj2 are both interned symbols and
(string=? (symbol->string obj1) (symbol->string obj2)) => #t- obj1 and obj2 are both numbers, are numerically equal according to the
=
procedure, and are either both exact or both inexact (see Numbers).- obj1 and obj2 are both characters and are the same character according to the
char=?
procedure (see Characters).- both obj1 and obj2 are the empty list.
- obj1 and obj2 are procedures whose location tags are equal.
- obj1 and obj2 are pairs, vectors, strings, bit strings, records, cells, or weak pairs that denote the same locations in the store.
The
eqv?
procedure returns#f
if:
- obj1 and obj2 are of different types.
- one of obj1 and obj2 is
#t
but the other is#f
.- obj1 and obj2 are symbols but
(string=? (symbol->string obj1) (symbol->string obj2)) => #f- one of obj1 and obj2 is an exact number but the other is an inexact number.
- obj1 and obj2 are numbers for which the
=
procedure returns#f
.- obj1 and obj2 are characters for which the
char=?
procedure returns#f
.- one of obj1 and obj2 is the empty list but the other is not.
- obj1 and obj2 are procedures that would behave differently (return a different value or have different side effects) for some arguments.
- obj1 and obj2 are pairs, vectors, strings, bit strings, records, cells, or weak pairs that denote distinct locations.
Some examples:
(eqv? 'a 'a) => #t (eqv? 'a 'b) => #f (eqv? 2 2) => #t (eqv? '() '()) => #t (eqv? 100000000 100000000) => #t (eqv? (cons 1 2) (cons 1 2)) => #f (eqv? (lambda () 1) (lambda () 2)) => #f (eqv? #f 'nil) => #f (let ((p (lambda (x) x))) (eqv? p p)) => #tThe following examples illustrate cases in which the above rules do not fully specify the behavior of
eqv?
. All that can be said about such cases is that the value returned byeqv?
must be a boolean.(eqv? "" "") => unspecified (eqv? '#() '#()) => unspecified (eqv? (lambda (x) x) (lambda (x) x)) => unspecified (eqv? (lambda (x) x) (lambda (y) y)) => unspecifiedThe next set of examples shows the use of
eqv?
with procedures that have local state.gen-counter
must return a distinct procedure every time, since each procedure has its own internal counter.gen-loser
, however, returns equivalent procedures each time, since the local state does not affect the value or side effects of the procedures.(define gen-counter (lambda () (let ((n 0)) (lambda () (set! n (+ n 1)) n)))) (let ((g (gen-counter))) (eqv? g g)) => #t (eqv? (gen-counter) (gen-counter)) => #f (define gen-loser (lambda () (let ((n 0)) (lambda () (set! n (+ n 1)) 27)))) (let ((g (gen-loser))) (eqv? g g)) => #t (eqv? (gen-loser) (gen-loser)) => unspecified (letrec ((f (lambda () (if (eqv? f g) 'both 'f))) (g (lambda () (if (eqv? f g) 'both 'g))) (eqv? f g)) => unspecified (letrec ((f (lambda () (if (eqv? f g) 'f 'both))) (g (lambda () (if (eqv? f g) 'g 'both))) (eqv? f g)) => #fObjects of distinct types must never be regarded as the same object.
Since it is an error to modify constant objects (those returned by literal expressions), the implementation may share structure between constants where appropriate. Thus the value of
eqv?
on constants is sometimes unspecified.(let ((x '(a))) (eqv? x x)) => #t (eqv? '(a) '(a)) => unspecified (eqv? "a" "a") => unspecified (eqv? '(b) (cdr '(a b))) => unspecifiedRationale: The above definition of
eqv?
allows implementations latitude in their treatment of procedures and literals: implementations are free either to detect or to fail to detect that two procedures or two literals are equivalent to each other, and can decide whether or not to merge representations of equivalent objects by using the same pointer or bit pattern to represent both.
eq?
is similar toeqv?
except that in some cases it is capable of discerning distinctions finer than those detectable byeqv?
.
eq?
andeqv?
are guaranteed to have the same behavior on symbols, booleans, the empty list, pairs, records, and non-empty strings and vectors.eq?
's behavior on numbers and characters is implementation-dependent, but it will always return either true or false, and will return true only wheneqv?
would also return true.eq?
may also behave differently fromeqv?
on empty vectors and empty strings.(eq? 'a 'a) => #t (eq? '(a) '(a)) => unspecified (eq? (list 'a) (list 'a)) => #f (eq? "a" "a") => unspecified (eq? "" "") => unspecified (eq? '() '()) => #t (eq? 2 2) => unspecified (eq? #\A #\A) => unspecified (eq? car car) => #t (let ((n (+ 2 3))) (eq? n n)) => unspecified (let ((x '(a))) (eq? x x)) => #t (let ((x '#())) (eq? x x)) => #t (let ((p (lambda (x) x))) (eq? p p)) => #tRationale: It will usually be possible to implement
eq?
much more efficiently thaneqv?
, for example, as a simple pointer comparison instead of as some more complicated operation. One reason is that it may not be possible to computeeqv?
of two numbers in constant time, whereaseq?
implemented as pointer comparison will always finish in constant time.eq?
may be used likeeqv?
in applications using procedures to implement objects with state since it obeys the same constraints aseqv?
.
equal?
recursively compares the contents of pairs, vectors, and strings, applyingeqv?
on other objects such as numbers, symbols, and records. A rule of thumb is that objects are generallyequal?
if they print the same.equal?
may fail to terminate if its arguments are circular data structures.(equal? 'a 'a) => #t (equal? '(a) '(a)) => #t (equal? '(a (b) c) '(a (b) c)) => #t (equal? "abc" "abc") => #t (equal? 2 2) => #t (equal? (make-vector 5 'a) (make-vector 5 'a)) => #t (equal? (lambda (x) x) (lambda (y) y)) => unspecified