Node: Equivalence predicates, Next: , Previous: Standard Procedures, Up: Standard Procedures



Equivalence predicates

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?.

eqv? obj1 obj2 R5RS
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. This relation is left slightly open to interpretation, but the following partial specification of eqv? holds for all implementations of Scheme.

The eqv? procedure returns #t if:

  • obj1 and obj2 are both #t or both #f.
  • obj1 and obj2 are both symbols and
                   (string=? (symbol->string obj1)
                             (symbol->string obj2))
                                        =>  #t
                   
    Note: This assumes that neither obj1 nor obj2 is an "uninterned symbol".
  • obj1 and obj2 are both keywords and
                   (string=? (keyword->string obj1)
                             (keyword->string obj2))
                                        =>  #t
                   
  • obj1 and obj2 are both numbers, are numerically equal (see see =), and are either both exact or both inexact.
  • obj1 and obj2 are both characters and are the same character according to the char=? procedure (see see char=).
  • both obj1 and obj2 are the empty list.
  • obj1 and obj2 are pairs, vectors, or strings that denote the same locations in the store.
  • obj1 and obj2 are procedures whose location tags are equal.

Note: STKLOS extends R5RS eqv? to take into account the keyword type.

Here are some examples:

          (eqv? 'a 'a)                     =>  #t
          (eqv? 'a 'b)                     =>  #f
          (eqv? 2 2)                       =>  #t
          (eqv? :foo :foo)                 =>  #t
          (eqv? :foo :bar)                 =>  #f
          (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
          

Note: In fact, the value returned by STKLOS depends of the way code is entered and can yield #t in some cases and #f in others.

See R5RS for more details on eqv?

eq? obj1 obj2 R5RS
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, keywords, booleans, the empty list, pairs, procedures, 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.

Note: STKLOS extends R5RS eq? to take into account the keyword type.

Note: In STKLOS, comparison of character returns #t for identical characters and #f otherwise.

          (eq? 'a 'a)                     =>  #t
          (eq? '(a) '(a))                 =>  unspecified
          (eq? (list 'a) (list 'a))       =>  #f
          (eq? "a" "a")                   =>  unspecified
          (eq? "" "")                     =>  unspecified
          (eq? :foo :foo)                 =>  #t
          (eq? :foo :bar)                 =>  #f
          (eq? '() '())                   =>  #t
          (eq? 2 2)                       =>  unspecified
          (eq? #\A #\A)                   =>  #t (unspecified in R5RS)
          (eq? car car)                   =>  #t
          (let ((n (+ 2 3)))
            (eq? n n))                    =>  #t (unspecified in R5RS)
          (let ((x '(a)))
            (eq? x x))                    =>  #t
          (let ((x '#()))
            (eq? x x))                    =>  #t
          (let ((p (lambda (x) x)))
            (eq? p p))                    =>  #t
          (eq? :foo :foo)		   =>  #t
          (eq? :bar bar:)		   =>  #t
          (eq? :bar :foo)                 =>  #f
          

equal? obj1 obj2 R5RS
Equal? recursively compares the contents of pairs, vectors, and strings, applying eqv? on other objects such as numbers and symbols. 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