<< Previous exercise (2.79) | Index | Next exercise (2.81) >>
A type-recursive version
;; Version - 1 (define (=zero? data) (cond ((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.
meteorgan