6.2. Generic Equivalence and Type Predicates


6.2. Generic Equivalence and Type Predicates

This section describes the basic Scheme predicates (procedures returning one of the boolean values #t or #f) for determining the type of an object or the equivalence of two objects. The equivalence predicates eq?, eqv?, and equal? are discussed first, followed by the type predicates.

(eq? obj1 obj2)

procedure

returns: #t if obj1 and obj2 are identical, #f otherwise

In most Scheme systems, two objects are considered identical if they are represented internally by the same pointer value and distinct (not identical) if they are represented internally by different pointer values, although other criteria, such as time-stamping, are possible.

Although the particular rules for object identity vary somewhat from system to system, the following rules always hold.

  • Two objects of different types (booleans, the empty list, pairs, numbers, characters, strings, vectors, symbols, and procedures) are distinct.

  • Two objects of the same type with different contents or values are distinct.

  • The boolean object #t is identical to itself wherever it appears, and #f is identical to itself wherever it appears, but #t and #f are distinct.

  • The empty list () is identical to itself wherever it appears.

  • Two symbols (created by read or by string->symbol) are identical if and only if they have the same name (by string=?).

  • A quoted pair, vector, or string is identical to itself, as is a pair, vector, or string created by an application of cons, vector, string, etc. Two pairs, vectors, or strings created by different applications of cons, vector, string, etc., are distinct. One consequence is that cons, for example, may be used to create a unique object distinct from all other objects.

  • Two procedures that may behave differently are distinct. A procedure created by an evaluation of a lambda expression is identical to itself. Two procedures created by the same lambda expression at different times, or by similar lambda expressions, may or may not be identical.

eq? cannot be used to compare numbers and characters reliably. Although every inexact number is distinct from every exact number, two exact numbers, two inexact numbers, or two characters with the same value may or may not be identical.

Since constant objects are immutable, i.e., it is an error to modify one, all or portions of different quoted constants or self-evaluating literals may be represented internally by the same object. Thus, eq? may return #t when applied to equal parts of different immutable constants.

 (eq? 'a 3)  #f (eq? #t 't)  #f (eq? "abc" 'abc)  #f (eq? "hi" '(hi))  #f (eq? #f '())  #f (eq? 9/2 7/2)  #f (eq? 3.4 53344)  #f (eq? 3 3.0)  #f (eq? 1/3 #i1/3)  #f (eq? 9/2 9/2)  unspecified (eq? 3.4 (+ 3.0 .4))  unspecified (let ((x (* 12345678987654321 2)))   (eq? x x))  unspecified (eq? #\a #\b)  #f (eq? #\a #\a)  unspecified (let ((x (string-ref "hi" 0)))   (eq? x x))  unspecified (eq? #t #t)  #t (eq? #f #f)  #t (eq? #t #f)  #f (eq? (null? '()) #t)  #t (eq? (null? '(a)) #f)  #t (eq? (cdr '(a)) '())  #t (eq? 'a 'a)  #t (eq? 'a 'b)  #f (eq? 'a (string->symbol "a"))  #t (eq? '(a) '(b))  #f (eq? '(a) '(a))  unspecified (let ((x '(a . b))) (eq? x x))  #t (let ((x (cons 'a 'b)))   (eq? x x))  #t (eq? (cons 'a 'b) (cons 'a 'b))  #f (eq? "abc" "cba")  #f (eq? "abc" "abc")  unspecified (let ((x "hi")) (eq? x x))  #t (let ((x (string #\h #\i))) (eq? x x))  #t (eq? (string #\h #\i)      (string #\h #\i))  #f (eq? '#(a) '#(b))  #f (eq? '#(a) '#(a))  unspecified (let ((x '#(a))) (eq? x x))  #t (let ((x (vector 'a)))   (eq? x x))  #t (eq? (vector 'a) (vector 'a))  #f (eq? car car)  #t (eq? car cdr)  #f (let ((f (lambda (x) x)))   (eq? f f))  #t (let ((f (lambda () (lambda (x) x))))   (eq? (f) (f)))  unspecified (eq? (lambda (x) x) (lambda (y) y))  unspecified (let ((f (lambda (x)            (lambda ()              (set! x (+ x 1))              x)))) (eq? (f 0) (f 0)))  #f 

(eqv? obj1 obj2)

procedure

returns: #t if obj1 and obj2 are equivalent, #f otherwise

eqv? is similar to eq? except that eqv? is guaranteed to return #t for two exact numbers, two inexact numbers, or two characters with the same value (by = or char=?). eqv? is less implementation-dependent but generally more expensive than eq?. eqv? might be defined as follows.

 (define eqv?   (lambda (x y)     (cond       ((eq? x y))       ((number? x)        (and (number? y)             (if (exact? x)                 (and (exact? y) (= x y))                 (and (inexact? y) (= x y)))))       ((char? x) (and (char? y) (char=? x y)))       (else #f)))) (eqv? 'a 3)  #f (eqv? #t 't)  #f (eqv? "abc" 'abc)  #f (eqv? "hi" '(hi))  #f (eqv? #f '())  #f (eqv? 9/2 7/2)  #f (eqv? 3.4 53344)  #f (eqv? 3 3.0)  #f (eqv? 1/3 #i1/3)  #f (eqv? 9/2 9/2)  #t (eqv? 3.4 (+ 3.0 .4))  #t (let ((x (* 12345678987654321 2)))   (eqv? x x))  #t (eqv? #\a #\b)  #f (eqv? #\a #\a)  #t (let ((x (string-ref "hi" 0)))   (eqv? x x))  #t (eqv? #t #t)  #t (eqv? #f #f)  #t (eqv? #t #f)  #f (eqv? (null? '()) #t)  #t (eqv? (null? '(a)) #f)  #t (eqv? (cdr '(a)) '())  #t (eqv? 'a 'a)  #t (eqv? 'a 'b)  #f (eqv? 'a (string->symbol "a"))  #t (eqv? '(a) '(b))  #f (eqv? '(a) '(a))  unspecified (let ((x '(a . b))) (eqv? x x))  #t (let ((x (cons 'a 'b)))   (eqv? x x))  #t (eqv? (cons 'a 'b) (cons 'a 'b))  #f (eqv? "abc" "cba")  #f (eqv? "abc" "abc")  unspecified (let ((x "hi")) (eqv? x x))  #t (let ((x (string #\h #\i))) (eqv? x x))  #t (eqv? (string #\h #\i)       (string #\h #\i))  #f (eqv? '#(a) '#(b))  #f (eqv? '#(a) '#(a))  unspecified (let ((x '#(a))) (eqv? x x))  #t (let ((x (vector 'a)))   (eqv? x x))  #t (eqv? (vector 'a) (vector 'a))  #f (eqv? car car)  #t (eqv? car cdr)  #f (let ((f (lambda (x) x)))   (eqv? f f))  #t (let ((f (lambda () (lambda (x) x))))   (eqv? (f) (f)))  unspecified (eqv? (lambda (x) x) (lambda (y) y))  unspecified (let ((f (lambda (x)            (lambda ()              (set! x (+ x 1))              x)))) (eqv? (f 0) (f 0)))  #f 

(equal? obj1 obj2)

procedure

returns: #t if obj1 and obj2 have the same structure and contents, #f otherwise

Two objects are equal if they are equivalent according to eqv? or if they are strings that are string=?, pairs whose cars and cdrs are equal, or vectors of the same length whose corresponding elements are equal.

equal? is recursively defined and must compare not only numbers and characters for equivalence but also pairs, strings, and vectors. The result is that equal? is less discriminating than either eq? or eqv?. It is also likely to be more expensive.

equal? might be defined as follows.

 (define equal?   (lambda (x y)     (cond       ((eqv? x y))       ((pair? x)        (and (pair? y)             (equal? (car x) (car y))             (equal? (cdr x) (cdr y))))       ((string? x) (and (string? y) (string=? x y)))       ((vector? x)        (and (vector? y)             (let ((n (vector-length x)))               (and (= (vector-length y) n)                    (let loop ((i 0))                      (or (= i n)                          (and (equal? (vector-ref x i) (vector-ref y i))                               (loop (+ i 1))))))))) (else #f)))) (equal? 'a 3)  #f (equal? #t 't)  #f (equal? "abc" 'abc)  #f (equal? "hi" '(hi))  #f (equal? #f '())  #f (equal? 9/2 7/2)  #f (equal? 3.4 53344)  #f (equal? 3 3.0)  #f (equal? 1/3 #i1/3)  #f (equal? 9/2 9/2)  #t (equal? 3.4 (+ 3.0 .4))  #t (let ((x (* 12345678987654321 2)))   (equal? x x))  #t (equal? #\a #\b)  #f (equal? #\a #\a)  #t (let ((x (string-ref "hi" 0)))   (equal? x x))  #t (equal? #t #t)  #t (equal? #f #f)  #t (equal? #t #f)  #f (equal? (null? '()) #t)  #t (equal? (null? '(a)) #f)  #t (equal? (cdr '(a)) '())  #t (equal? 'a 'a)  #t (equal? 'a 'b)  #f (equal? 'a (string->symbol "a"))  #t (equal? '(a) '(b))  #f (equal? '(a) '(a))  #t (let ((x '(a . b))) (equal? x x))  #t (let ((x (cons 'a 'b)))   (equal? x x))  #t (equal? (cons 'a 'b) (cons 'a 'b))  #t (equal? "abc" "cba")  #f (equal? "abc" "abc")  #t (let ((x "hi")) (equal? x x))  #t (let ((x (string #\h #\i))) (equal? x x))  #t (equal? (string #\h #\i)         (string #\h #\i))  #t (equal? '#(a) '#(b))  #f (equal? '#(a) '#(a))  #t (let ((x '#(a))) (equal? x x))  #t (let ((x (vector 'a)))   (equal? x x))  #t (equal? (vector 'a) (vector 'a))  #t (equal? car car)  #t (equal? car cdr)  #f (let ((f (lambda (x) x)))   (equal? f f))  #t (let ((f (lambda () (lambda (x) x))))   (equal? (f) (f)))  unspecified (equal? (lambda (x) x) (lambda (y) y))  unspecified (let ((f (lambda (x)            (lambda ()              (set! x (+ x 1))              x)))) (equal? (f 0) (f 0)))  #f 

(boolean? obj )

procedure

returns: #t if obj is either #t or #f, #f otherwise

 boolean? is equivalent to (lambda (x) (or (eq? x #t) (eq? x #f))). (boolean? #t)  #t (boolean? #f)  #t (boolean? 't)  #f (boolean? '())  #f 

(null? obj )

procedure

returns: #t if obj is the empty list, #f otherwise

null? is equivalent to (lambda (x) (eq? x '())).

 (null? '())  #t (null? '(a))  #f (null? (cdr '(a)))  #t (null? 3)  #f (null? #f)  #f 

(pair? obj )

procedure

returns: #t if obj is a pair, #f otherwise

 (pair? '(a b c))  #t (pair? '(3 . 4))  #t (pair? '())  #f (pair? '#(a b))  #f (pair? 3)  #f 

(number? obj )

procedure

returns: #t if obj is a number, #f otherwise

(complex? obj )

procedure

returns: #t if obj is a complex number, #f otherwise

(real? obj )

procedure

returns: #t if obj is a real number, #f otherwise

(rational? obj )

procedure

returns: #t if obj is a rational number, #f otherwise

(integer? obj )

procedure

returns: #t if obj is an integer, #f otherwise

These predicates form a hierarchy: any integer is rational, any rational is real, any real is complex, and any complex is numeric. Most implementations do not provide internal representations for irrational numbers, so all real numbers are typically rational as well.

 (integer? 1901)  #t (rational? 1901)  #t (real? 1901)  #t (complex? 1901)  #t (number? 1901)  #t (integer? -3.0)  #t (rational? -3.0)  #t (real? -3.0)  #t (complex? -3.0)  #t (number? -3.0)  #t (integer? 7.0+0.0i)  #t (rational? 7.0+0.0i)  #t (real? 7.0+0.0i)  #t (complex? 7.0+0.0i)  #t (number? 7.0+0.0i)  #t (integer? -2/3)  #f (rational? -2/3)  #t (real? -2/3)  #t (complex? -2/3)  #t (number? -2/3)  #t (integer? -2.345)  #f (rational? -2.345)  #t (real? -2.345)  #t (complex? -2.345)  #t (number? -2.345)  #t (integer? 3.2-2.01i)  #f (rational? 3.2-2.01i)  #f (real? 3.2-2.01i)  #f (complex? 3.2-2.01i)  #t (number? 3.2-2.01i)  #t (integer? 'a)  #f (rational? '(a b c))  #f (real? "3")  #f (complex? #(1 2))  #f (number? #\a)  #f 

(char? obj )

procedure

returns: #t if obj is a character, #f otherwise

 (char? 'a)  #f (char? 97)  #f (char? #\a)  #t (char? "a")  #f (char? (string-ref (make-string 1) 0))  #t 

(string? obj )

procedure

returns: #t if obj is a string, #f otherwise

 (string? "hi")  #t (string? 'hi)  #f (string? #\h)  #f 

(vector? obj )

procedure

returns: #t if obj is a vector, #f otherwise

 (vector? '#())  #t (vector? '#(a b c))  #t (vector? (vector 'a 'b 'c))  #t (vector? '())  #f (vector? '(a b c))  #f (vector? "abc")  #f 

(symbol? obj )

procedure

returns: #t if obj is a symbol, #f otherwise

 (symbol? 't)  #t (symbol? "t")  #f (symbol? '(t))  #f (symbol? #\t)  #f (symbol? 3)  #f (symbol? #t)  #f 

(procedure? obj )

procedure

returns: #t if obj is a procedure, #f otherwise

 (procedure? car)  #t (procedure? 'car)  #f (procedure? (lambda (x) x))  #t (procedure? '(lambda (x) x))  #f (call/cc procedure?)  #t 




The Scheme Programming Language
The Scheme Programming Language
ISBN: 026251298X
EAN: 2147483647
Year: 2003
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net