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

2.5.3 example: symbolic algebra

Author: jordyn

Created: 2021-02-15 Mon 16:09