Next: Numbers, Previous: Special Forms, Up: MIT/GNU Scheme [Contents][Index]
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:
#t
or both #f
.
(string=? (symbol->string obj1) (symbol->string obj2)) ⇒ #t
=
procedure, and are either both exact or both
inexact (see Numbers).
char=?
procedure (see Characters).
The eqv?
procedure returns #f
if:
#t
but the other is
#f
.
(string=? (symbol->string obj1) (symbol->string obj2)) ⇒ #f
=
procedure
returns #f
.
char=?
procedure returns #f
.
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)) ⇒ #t
The 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 by eqv?
must be a boolean.
(eqv? "" "") ⇒ unspecified (eqv? '#() '#()) ⇒ unspecified (eqv? (lambda (x) x) (lambda (x) x)) ⇒ unspecified (eqv? (lambda (x) x) (lambda (y) y)) ⇒ unspecified
The 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))
⇒ #f
Objects 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))) ⇒ unspecified
Rationale: 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 to eqv?
except that in some cases it is
capable of discerning distinctions finer than those detectable by
eqv?
.
eq?
and eqv?
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 when eqv?
would also return
true. eq?
may also behave differently from eqv?
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)) ⇒ #t
Rationale: It will usually be possible to implement eq?
much more
efficiently than eqv?
, for example, as a simple pointer
comparison instead of as some more complicated operation. One reason is
that it may not be possible to compute eqv?
of two numbers in
constant time, whereas eq?
implemented as pointer comparison will
always finish in constant time. eq?
may be used like eqv?
in applications using procedures to implement objects with state since
it obeys the same constraints as eqv?
.
equal?
recursively compares the contents of pairs, vectors, and
strings, applying eqv?
on other objects such as numbers, symbols,
and records. A rule of thumb is that objects are generally
equal?
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
Next: Numbers, Previous: Special Forms, Up: MIT/GNU Scheme [Contents][Index]