Next: , Previous: , Up: baselib   [Index]


4.5 Equivalence and procedure 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. The eqv? predicate is slightly less discriminating than eq?.

Procedure: eqv? obj1 obj2

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 and #f otherwise. This relation is left slightly open to interpretation, but the following partial specification of eqv? must hold for all implementations.

The eqv? procedure returns #t if one of the following holds:

The eqv? procedure returns #f if one of the following holds:

NOTE The eqv? procedure returning #t when obj1 and obj2 are number objects does not imply that = would also return #t when called with obj1 and obj2 as arguments.

(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

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.

(let ((p (lambda (x) x)))
  (eqv? p p))                   ⇒ unspecified

(eqv? "" "")                    ⇒ unspecified

(eqv? '#() '#())                ⇒ unspecified

(eqv? (lambda (x) x)
      (lambda (x) x))           ⇒ unspecified

(eqv? (lambda (x) x)
      (lambda (y) y))           ⇒ unspecified

(eqv? +nan.0 +nan.0)            ⇒ unspecified

The next set of examples shows the use of eqv? with procedures that have local state. Calls to gen-counter must return a distinct procedure every time, since each procedure has its own internal counter. Calls to gen-loser return procedures that behave equivalently when called. However, eqv? may not detect this equivalence.

(define gen-counter
  (lambda ()
    (let ((n 0))
      (lambda () (set! n (+ n 1)) n))))
(let ((g (gen-counter)))
  (eqv? g g))           ⇒  unspecified
(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))           ⇒  unspecified
(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

Implementations may share structure between constants where appropriate. Furthermore, a constant may be copied at any time by the implementation so as to exist simultaneously in different sets of locations. Thus the value of eqv? on constants is sometimes implementation–dependent.

(eqv? '(a) '(a))                 ⇒ unspecified
(eqv? "a" "a")                   ⇒ unspecified
(eqv? '(b) (cdr '(a b)))         ⇒ unspecified
(let ((x '(a)))
  (eqv? x x))                    ⇒ #t
Procedure: eq? obj1 obj2

The eq? predicate is similar to eqv? except that in some cases it is capable of discerning distinctions finer than those detectable by eqv?.

The eq? and eqv? predicates are guaranteed to have the same behavior on symbols, booleans, the empty list, pairs, procedures, non–empty strings, bytevectors, vectors, and records. The behavior of eq? on number objects and characters is implementation–dependent, but it always returns either #t or #f, and returns #t only when eqv? would also return #t. The eq? predicate may also behave differently from eqv? on empty vectors, empty bytevectors, 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))                    ⇒ unspecified
(let ((p (lambda (x) x)))
  (eq? p p))                    ⇒ unspecified
Procedure: equal? obj1 obj2

The equal? predicate returns #t if and only if the (possibly infinite) unfoldings of its arguments into regular trees are equal as ordered trees.

The equal? predicate treats pairs and vectors as nodes with outgoing edges, uses string=? to compare strings, uses bytevector=? to compare bytevectors (stdlib bytevector), and uses eqv? to compare other nodes.

(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? '#vu8(1 2 3 4 5)
        (u8-list->bytevector
         '(1 2 3 4 5))          ⇒  #t

(equal? (lambda (x) x)
        (lambda (y) y))         ⇒  unspecified

(let* ((x (list 'a))
       (y (list 'a))
       (z (list x y)))
  (list (equal? z (list y x))
        (equal? z (list x x)))) ⇒  (#t #t)

NOTE As Vicare extensions: structs are compared with struct=? and R6RS records are compared with record=?.

NOTE The equal? procedure must always terminate, even if its arguments contain cycles.

Procedure predicate

Procedure: procedure? obj

Return #t if obj is a procedure, otherwise return #f.

(procedure? car)                        ⇒ #t
(procedure? 'car)                       ⇒ #f
(procedure? (lambda (x) (* x x)))       ⇒ #t
(procedure? '(lambda (x) (* x x)))      ⇒ #f

Next: , Previous: , Up: baselib   [Index]