notes.org 3.4 KB

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