* 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 #+BEGIN_SRC scheme (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)) #+END_SRC to install the package for ord numbers (get and put are assumed but not implemented): #+BEGIN_SRC scheme (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) #+END_SRC users can create ordinary nums with this: #+BEGIN_SRC scheme (define (make-scheme-number n) ((get 'make 'scheme-number) n)) #+END_SRC 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 #+BEGIN_SRC scheme (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)))) #+END_SRC 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: #+BEGIN_SRC scheme (define (scheme-number->complex n) (make-complex-from-real-imag (contents n) 0)) #+END_SRC these coercions can be logged in one of those tables: #+BEGIN_SRC scheme (put-coercion 'scheme-number 'complex scheme-number->complex) #+END_SRC heres an impl: #+BEGIN_SRC scheme (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))))))) #+END_SRC HIERARCHIES OF TYPES wow... getting dangerously close to inheritance here hierarchies can be linear (easier to engineer) or else a tree of types ** 2.5.3 example: symbolic algebra