Systems with Generic Operations • Previous section: designed systems in which data Topic 15 objects can be represented in more than one way • Key idea: link the code that specifies the data Generic Arithmetic Operations operations to the several representations via generic interface procedures. • Extend this idea: define operations that are generic over different representations AND over differet kinds of arguments. Section 2.5.1 & 2.5.2 • Several different arithmetic packages: regular, rational, complex – let’s put them all together Fall 2008 Programming Development 1 Fall 2008 Programming Development 2 Techniques Techniques Generic Use of Numbers Generic operations • We want to do arithmetic with any combination of ordinary numbers, rational numbers and complex numbers • We'll use the data-directed programming style • Ordinary Scheme numbers will have to be represented and tagged like all the rest Fall 2008 Programming Development 3 Fall 2008 Programming Development 4 Techniques Techniques Basic arithmetic operations Scheme number package ; generic operations definitions to use we would need to ; attach a tag to each kind of number and cause the ; package for handling ordinary scheme numbers ; generic procedure to dispatch the appropriate package ; note the key is (scheme-number scheme-number) ; for the data types of its arugments ; since each takes two arguments, both of which (define (add x y) ; are ordinary scheme-numbers (apply-generic 'add x y)) (define (install-scheme-number-package) (define (sub x y) (define (tag x) (apply-generic 'sub x y)) (attach-tag 'scheme-number x)) (define (mul x y) (put 'add (apply-generic 'mul x y)) '(scheme-number scheme-number) (define (div x y) (lambda (x y) (tag (+ x y)))) (apply-generic 'div x y)) Fall 2008 Programming Development 5 Fall 2008 Programming Development 6 Techniques Techniques 1
continued Scheme-number constructor (put 'sub '(scheme-number scheme-number) ; user of the scheme-number package will create (lambda (x y) (tag (- x y)))) ; tagged ordinary numbers by means of the make (put 'mul ; procedure '(scheme-number scheme-number) (define (make-scheme-number n) (lambda (x y) (tag (* x y)))) ((get 'make 'scheme-number) n)) (put 'div '(scheme-number scheme-number) (lambda (x y) (tag (/ x y)))) (put 'make 'scheme-number (lambda (x) (tag x))) 'done) Fall 2008 Programming Development 7 Fall 2008 Programming Development 8 Techniques Techniques Rational number package rational package continued ; package for performing rational arithmetic ; interface to rest of system (define (install-rational-package) (put 'add ; internal procedures '(rational rational) (define numer car) (lambda (x y) (define denom cdr) (tag (make-rat (define (make-rat n d) (+ (* (numer x) (denom y)) (let ((g (gcd n d))) (* (numer y) (denom x))) (cons (/ n g) (/ d g)))) (* (denom x) (denom y)))))) (define (tag x) (attach-tag 'rational x)) Fall 2008 Programming Development 9 Fall 2008 Programming Development 10 Techniques Techniques subtraction multiplication (put 'sub (put 'mul '(rational rational) '(rational rational) (lambda (x y) (lambda (x y) (tag (make-rat (tag (make-rat (- (* (numer x) (denom y)) (* (numer x) (numer y)) (* (numer y) (denom x))) (* (denom x) (denom y)))))) (* (denom x) (denom y)))))) Fall 2008 Programming Development 11 Fall 2008 Programming Development 12 Techniques Techniques 2
division constructor code (put 'div (put 'make '(rational rational) 'rational (lambda (x y) (lambda (n d) (tag (make-rat n d)))) (tag (make-rat 'done) (* (numer x) (denom y)) (* (denom x) (numer y)))))) (define (make-rational n d) ((get 'make 'rational) n d)) Fall 2008 Programming Development 13 Fall 2008 Programming Development 14 Techniques Techniques Complex number package Addition ; package for handling complex numbers (define (install-complex-package) (put 'add ; imported procedures from rectangular and '(complex complex) ; polar packages (lambda (z1 z2) (define (make-from-real-imag x y) (tag (make-from-real-imag ((get 'make-from-real-imag 'rectangular) (+ (real-part z1) x (real-part z2)) y)) (+ (imag-part z1) ; interface to rest of the system (imag-part z2)))))) (define (make-from-mag-ang r a) ((get 'make-from-mag-ang 'polar) r a)) (define (tag z) (attach-tag 'complex z)) Fall 2008 Programming Development 15 Fall 2008 Programming Development 16 Techniques Techniques Subtraction Multiplication (put 'sub (put 'mul '(complex complex) '(complex complex) (lambda (z1 z2) (lambda (z1 z2) (tag (make-from-real-imag (tag (make-from-mag-ang (- (real-part z1) (* (magnitude z1) (real-part z2)) (magnitude z2)) (+ (angle z1) (angle z2)))))) (- (imag-part z1) (imag-part z2)))))) Fall 2008 Programming Development 17 Fall 2008 Programming Development 18 Techniques Techniques 3
Division Constructors (put 'div (put 'make-from-real-imag '(complex complex) 'complex (lambda (z1 z2) (lambda (x y) (tag (make-from-mag-ang (tag (make-from-real-imag x y)))) (/ (magnitude z1) (put 'make-from-mag-ang (magnitude z2)) 'complex (- (angle z1) (angle z2)))))) (lambda (r a) (tag (make-from-mag-ang r a)))) 'done) Fall 2008 Programming Development 19 Fall 2008 Programming Development 20 Techniques Techniques Complex Numbers – two levels of continued export ; exporting complex numbers to outside world • Notice that complex numbers for a two-level tag system. A typical complex number e.g., 1 + 2i in rectangular form will be represented as (define (make-complex-from-real-imag x y) (complex (rectangular 1 . 2)) ((get 'make-from-real-imag 'complex) x y)) First tag directs to complex number package, once (define (make-complex-from-mag-ang r a) there, second tag directs to rectangular package. ((get 'make-from-mag-ang 'complex) r a)) Fall 2008 Programming Development 21 Fall 2008 Programming Development 22 Techniques Techniques Installing it all Combining Data of Different Types ; run the procedures to set up the operations table One approach: ; operation-table will hold the triples of (put 'add ; operations, their type, and the associated action '(complex scheme-number) (install-scheme-number-package) (lambda (z x) (install-rational-package) (tag (make-from-real-imag (install-rectangular-package) (+ (real-part z) x) (install-polar-package) (imag-part z)))))) (install-complex-package) Awkward when there are many combinations Fall 2008 Programming Development 23 Fall 2008 Programming Development 24 Techniques Techniques 4
A better way – transform objects Coerce a rational number into a of one type into another type complex one ; puts a procedure for coercing a rational ;; to allow operations between mixed types ; number into a complex number ;; must allow coercion between types (put 'coerce ; puts a procedure for coercing a scheme-number 'rational ; into a rational number (lambda (r) (put 'coerce (make-complex-from-real-imag 'scheme-number (/ (car (contents r)) (lambda (n) (cdr (contents r))) (make-rational (contents n) 1))) Fall 2008 Programming Development 25 Fall 2008 Programming Development 26 Techniques Techniques Precedence info to control Revised apply-generic coercion When a mixed procedure is encountered, ; new apply-generic procedure attempts to must try to coerce arguments. Thus, ; do type coercion if no operator with the must know which way coercion can occur. ; appropriate type is defined in the operation To do this, put precedence information in the operations table. ; table (define (apply-generic op . args) ;; must put precedence information in the operation (let ((type-tags (map type-tag args))) ;; table to control coercion (let ((proc (get op type-tags))) (put 'scheme-number 'rational 'precedence) (put 'scheme-number 'complex 'precedence) (put 'rational 'complex 'precedence) Fall 2008 Programming Development 27 Fall 2008 Programming Development 28 Techniques Techniques continued (if proc ; otherwise, attempt to do coercion if ; there are two arguments ; if procedure of appropraite type (if (= (length args) 2) ; exists apply that procedure (let ((t1 (car type-tags)) (apply proc (map contents args)) (t2 (cadr type-tags)) (a1 (car args)) (a2 (cadr args))) (let ((t1up (get 'coerce t1)) (t2up (get 'coerce t2)) (p1 (get t1 t2)) (p2 (get t2 t1))) Fall 2008 Programming Development 29 Fall 2008 Programming Development 30 Techniques Techniques 5
; t1up and t2up contain coercion ; procedures if they exist ; p1 and p2 tell whether precedence is correct (else (cond (p1 (error (apply-generic op "no method" (t1up a1) (list a2)) op (p2 (apply-generic type-tags)))))) op (error "no method" a1 (list op type-tags))))))) (t2up a2))) Fall 2008 Programming Development 31 Fall 2008 Programming Development 32 Techniques Techniques 6
Recommend
More recommend