<< Previous exercise (2.79) | Index | Next exercise (2.81) >>


 (define (=zero? x) (apply-generic '=zero? x)) 
 ;; add into scheme-number-package 
 (put '=zero? 'scheme-number (lambda (x) (= x 0))) 
 ;; add into rational-number-package 
 (put '=zero? 'rational-number  
          (lambda (x) (= (numer x) 0))) 
 ;; add into complex-number-package 
 (put '=zero? 'complex-number 
          (lambda (x) (= (real-part x) (imag-part x) 0))) 


A type-recursive version

 ;; Version - 1 
 (define (=zero? data) 
    ((number? data) (= data 0)) 
    ((eq? 'rational (type-tag data)) 
     (=zero? (contents data))) 
    ((eq? 'complex (type-tag data)) 
     (and (=zero? (real-part data)) 
          (=zero? (imag-part data)))) 
    (else (error "xxx")))) 
 ;; Version -2 
 (define (=zero? data) 
   (apply-generic '=zero? data)) 
 (define (install-scheme-number-package) 
   (put '=zero? '(scheme-number) 
        (lambda (x) (= x 0)))) ; scheme-number is the "base-type" 
 (define (install-rational-number-package) 
   (put '=zero? '(rational) 
        (lambda (x) (=zero? (numer x) 0)))) ;the numer part might be another type of number, for example a rational number 
 (define (install-complex-number-package) 
   (put '=zero? '(complex) 
        (lambda (x) 
          (and (=zero? (real-part x))  ; ibid 
               (=zero? (imag-part x)))))) ;ibid 


It's worth noting that defining =zero? in terms of itself as the answer above does, allows for greater flexibility. For instance we can have a rational number whose numer is a complex number. However, I do have slight modification to the answer above:

 (put '=zero? '(rectangular) (lambda (x) (and (=zero? (real-part x)) 
                                              (=zero? (imag-part x))))) 
 (put '=zero? '(polar) (lambda (x) (=zero? (magnitude x)))) 
 (put '=zero? '(complex) =zero?) ;; see ex 2.77. runs apply-generic twice. 

This approach is more abstract, and is more efficient when dealing with polar numbers as there's no need to convert from one from to the other.