2.5 Systems with Generic Operations
programs that use numbers ----------| add sub mul div |------------ generic arithmetic package --| add-rat |-+-| add-comp |-+---| + |--- | sub-rat | | | sub-comp | | | - | | mul-rat | | | mul-comp | | | * | | div-rat | | | div-comp | | | / | | | rational | complex | ordinary arithmetic | arithmetic | arithmetic |------+-------| | rect | polar | ----------------------------------------- list structure & primitive machine arithmetic
2.5.1 generic arithmetic operations
(define (add x y) (apply-generic 'add x y)) (define (sub x y) (apply-generic 'sub x y)) (define (mul x y) (apply-generic 'mul x y)) (define (div x y) (apply-generic 'div x y))
to install the package for ord numbers (get and put are assumed but
not implemented):
(define (install-scheme-number-package) (define (tag x) (attach-tag 'scheme-number x)) (put 'add '(scheme-number scheme-number) (λ (x y) (tag (+ x y)))) (put 'sub '(scheme-number scheme-number) (λ (x y) (tag (- x y)))) (put 'mul '(scheme-number scheme-number) (λ (x y) (tag (* x y)))) (put 'div '(scheme-number scheme-number) (λ (x y) (tag (/ x y)))) (put 'make 'scheme-number (λ (x) (tag x))) 'done)
users can create ordinary nums with this:
(define (make-scheme-number n) ((get 'make 'scheme-number) n))
see book for complete listing of
install-rational-package
and
install-complex-package.
2.5.2 combining data of different types
how to combine one type with another?
we could add this to the complex package
(define (add-complex-to-schemenum z x) (make-from-real-imag (+ (real-part z) x) (imag-part z))) (put 'add '(complex scheme-number) (λ (z x) (tag (add-complex-to-schemenum z x))))
this is operational but is cumbersome
COERCION
in the general situation of completely unrelated operations acting on
completely unrelated types, implementing explicit cross-type
operations is clumsy but also the only way.
BUT we can do better by doing type coercion
here's one:
(define (scheme-number->complex n) (make-complex-from-real-imag (contents n) 0))
these coercions can be logged in one of those tables:
(put-coercion 'scheme-number 'complex scheme-number->complex)
heres an impl:
(define (apply-generic op . args) (let ((type-tags (map type-tag args))) (let ((proc (get op type-tags))) (if proc (apply proc (map contents args)) (if (= (length args 2) (let ((type1 (car type-tags)) (type2 (cadr type-tags)) (a1 (car args)) (a2 (cadr args))) (let ((t1->t2 (get-coercion type1 type2)) (t2->t1 (get-coercion type2 type1))) (cond (t1->t2 (apply-generic op (t1->t2 a1) a2)) (t2->t1 (apply-generic op a1 (t2->t1 a2))) (else (error "no method for these types" (list op type-tags)))))) (error "no method for these types" (list op type-tags)))))))
HIERARCHIES OF TYPES
wow… getting dangerously close to inheritance here
hierarchies can be linear (easier to engineer) or else a tree of types