#lang sicp (#%require racket/trace) ;; This file covers exercises 2.78 to 2.97. ;;;from section 1.2.5, for Section 2.1.1 (define (gcd a b) (if (= b 0) a (gcd b (remainder a b)))) ;;;----------- ;;;from section 3.3.3 for section 2.4.3 ;;; to support operation/type table for data-directed dispatch (define (assoc key records) (cond ((null? records) false) ((equal? key (caar records)) (car records)) (else (assoc key (cdr records))))) (define (make-table) (let ((local-table (list '*table*))) (define (lookup key-1 key-2) (let ((subtable (assoc key-1 (cdr local-table)))) (if subtable (let ((record (assoc key-2 (cdr subtable)))) (if record (cdr record) false)) false))) (define (insert! key-1 key-2 value) (let ((subtable (assoc key-1 (cdr local-table)))) (if subtable (let ((record (assoc key-2 (cdr subtable)))) (if record (set-cdr! record value) (set-cdr! subtable (cons (cons key-2 value) (cdr subtable))))) (set-cdr! local-table (cons (list key-1 (cons key-2 value)) (cdr local-table))))) 'ok) (define (dispatch m) (cond ((eq? m 'lookup-proc) lookup) ((eq? m 'insert-proc!) insert!) (else (error "Unknown operation -- TABLE" m)))) dispatch)) (define operation-table (make-table)) (define get (operation-table 'lookup-proc)) (define put (operation-table 'insert-proc!)) (define coercion-table (make-table)) (define get-coercion (coercion-table 'lookup-proc)) (define put-coercion (coercion-table 'insert-proc!)) ;; Apply generic ;;(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)) ;; (error ;; "No method for these types -- APPLY-GENERIC" ;; (list op type-tags)))))) ;; Number tower. Ignores possibility of one of the arguments ;; not being in the tower. Maybe fix later. (define (lower-in-tower? t1 t2) (define tower '(integer rational scheme-number complex)) (define (tower-iter tower) (cond ((null? tower) (error "Not in tower" (list t1 t2))) ((eq? (car tower) t1) #t) ((eq? (car tower) t2) #f) (else (tower-iter (cdr tower))))) (if (eq? t1 t2) #f (tower-iter tower))) (define tower '(integer rational scheme-number complex)) (define (transform-type x tower) (define (next-type type tower) (cond ((or (null? tower) (null? (cdr tower))) '()) ((eq? type (car tower)) (cadr tower)) (else (next-type type (cdr tower))))) (and (type-tagged? x) (let* ((type (type-tag x)) (proj-type (next-type type tower))) (if (null? proj-type) '() ((get-coercion type proj-type) (contents x)))))) (define (raise x) (transform-type x tower)) (define (project x) (transform-type x (reverse tower))) (define (apply-generic op . args) (define (coerce-to t) (letrec ((coerce (lambda (arg) (cond ((eq? (type-tag arg) t) arg) ((lower-in-tower? (type-tag arg) t) (coerce (raise arg))) (else '()))))) coerce)) (define (any-empty-list l) (cond ((null? l) #f) ((eq? (car l) '()) #t) (else (any-empty-list (cdr l))))) (define (coerce-args args type-tags) (if (null? type-tags) '() (let* ((type (car type-tags)) (coerced-args (map (coerce-to type) args))) (if (not (any-empty-list coerced-args)) coerced-args (coerce-args args (cdr type-tags)))))) (let* ((type-tags (map type-tag args)) (proc (get op type-tags)) (result (if proc (apply proc (map contents args)) (if (> (length args) 1) (let ((coerced-args (coerce-args args type-tags))) (if (not (null? coerced-args)) (apply apply-generic (cons op coerced-args)) (error "Can't coerce arguments to a common type" (list op type-tags)))) (error "No matching operator for args" op args))))) result)) ;; scheme-number is for reals only (define (scheme-number? x) (and (real? x) (not (integer? x)))) (define (attach-tag type-tag contents) (cond ((eq? type-tag 'scheme-number) contents) (else (cons type-tag contents)))) (define (type-tag datum) (cond ((number? datum) 'scheme-number) ((pair? datum) (car datum)) (else (error "Bad tagged datum -- TYPE-TAG" datum)))) (define (contents datum) (cond ((number? datum) datum) ((pair? datum) (cdr datum)) (else (error "Bad tagged datum -- CONTENTS" datum)))) (define type-tagged? (lambda (x) (or (number? x) (pair? x)))) ;; Scheme numbers (define (install-scheme-number-package) (define (reduce-integers n d) (let ((g (gcd n d))) (list (/ n g) (/ d g)))) (define (tag x) (attach-tag 'scheme-number x)) (define (exp x y) (apply-generic 'exp x y)) (put 'add '(scheme-number scheme-number) (lambda (x y) (tag (+ x y)))) (put 'add3 '(scheme-number scheme-number scheme-number) (lambda (x y z) (tag (+ x y z)))) (put 'sub '(scheme-number scheme-number) (lambda (x y) (tag (- x y)))) (put 'mul '(scheme-number scheme-number) (lambda (x y) (tag (* x y)))) (put 'div '(scheme-number scheme-number) (lambda (x y) (tag (/ x y)))) (put 'negate '(scheme-number) (lambda (x) (tag (* -1 x)))) (put 'sine '(scheme-number) (lambda (x) (tag (sin x)))) (put 'cosine '(scheme-number) (lambda (x) (tag (cos x)))) (put 'square-root '(scheme-number) (lambda (x) (tag (sqrt x)))) (put 'greatest-common-divisor '(scheme-number scheme-number) (lambda (a b) (tag (gcd a b)))) (put 'reduce '(scheme-number scheme-number) (lambda (a b) (let ((reduced (reduce-integers a b))) (list (tag (car reduced)) (tag (cadr reduced)))))) (put 'equ? '(scheme-number scheme-number) =) (put '=zero? '(scheme-number) (lambda (x) (= x 0))) (put-coercion 'scheme-number 'complex (lambda (x) (make-complex-from-real-imag (tag x) (tag 0)))) (put-coercion 'scheme-number 'rational (lambda (x) (make-rational (round (* x 1000)) 1000))) (put 'exp '(scheme-number scheme-number) (lambda (x y) (tag (expt x y)))) (put 'make 'scheme-number (lambda (x) (tag x))) 'done) ;; Integers (define (install-integer-package) (define (tag x) (attach-tag 'integer x)) (define (raise-int x) (make-rational x 1)) (put 'add '(integer integer) (lambda (x y) (make-integer (+ x y)))) (put 'sub '(integer integer) (lambda (x y) (make-integer (- x y)))) (put 'div '(integer integer) (lambda (x y) (make-integer (/ x y)))) (put 'mul '(integer integer) (lambda (x y) (make-integer (* x y)))) (put 'negate '(integer) (lambda (x) (* -1 x))) (put 'sine '(integer) (lambda (x) (make-scheme-number (sin x)))) (put 'cosine '(integer) (lambda (x) (cos x))) (put 'square-root '(integer) (lambda (x) (make-scheme-number (sqrt x)))) (put 'arctan '(integer integer) (lambda (x y) (make-scheme-number (atan x y)))) (put 'equ? '(integer integer) (lambda (x y) (= x y))) (put-coercion 'integer 'rational raise-int) (put 'make 'integer (lambda (x) (tag (round x)))) 'done) ;; Rationals (define (install-rational-package) ;; internal procedures (define (numer x) (car x)) (define (denom x) (cdr x)) (define (make-rat n d) (let ((reduced (reduce n d))) (cons (car reduced) (cadr reduced)))) (define (add-rat x y) (make-rat (add (mul (numer x) (denom y)) (mul (numer y) (denom x))) (mul (denom x) (denom y)))) (define (sub-rat x y) (make-rat (sub (mul (numer x) (denom y)) (mul (numer y) (denom x))) (mul (denom x) (denom y)))) (define (mul-rat x y) (make-rat (mul (numer x) (numer y)) (mul (denom x) (denom y)))) (define (div-rat x y) (make-rat (mul (numer x) (denom y)) (mul (denom x) (numer y)))) (define (eq-rat x y) (and (= (numer x) (numer y)) (= (denom x) (denom y)))) (define (raise-rat x) (make-scheme-number (/ (numer x) (denom x)))) ;; interface to rest of the system (define (tag x) (attach-tag 'rational x)) (put 'add '(rational rational) (lambda (x y) (tag (add-rat x y)))) (put 'add3 '(rational rational rational) (lambda (x y z) (tag (add-rat x (add-rat y z))))) (put 'sub '(rational rational) (lambda (x y) (tag (sub-rat x y)))) (put 'mul '(rational rational) (lambda (x y) (tag (mul-rat x y)))) (put 'div '(rational rational) (lambda (x y) (tag (div-rat x y)))) (put 'negate '(rational) (lambda (x) (make-rational (* -1 (numer x)) (denom x)))) (put 'sine '(rational) (lambda (x) (sine (raise-rat x)))) (put 'cosine '(rational) (lambda (x) (cosine (raise-rat x)))) (put 'square-root '(rational) (lambda (x) (square-root (raise-rat x)))) (put 'arctan '(rational rational) (lambda (x y) (arctan (raise-rat x) (raise-rat y)))) (put 'equ? '(rational rational) eq-rat) (put '=zero? '(rational) (lambda (x) (equ? (numer x) (make-integer 0)))) (put-coercion 'rational 'scheme-number raise-rat) (put-coercion 'rational 'integer (lambda (x) (make-integer (/ (numer x) (denom x))))) (put 'make 'rational (lambda (n d) (tag (make-rat n d)))) 'done) ;;;----------- ;;;SECTION 2.4.3 ;; uses get/put (from 3.3.3) -- see ch2support.scm (define (install-rectangular-package) ;; internal procedures (define (real-part z) (car z)) (define (imag-part z) (cdr z)) (define (make-from-real-imag x y) (cons x y)) (define (magnitude z) (square-root (add (square (real-part z)) (square (imag-part z))))) (define (angle z) (arctan (imag-part z) (real-part z))) (define (make-from-mag-ang r a) (cons (mul r (cosine a)) (mul r (sine a)))) (define (negate z) (make-from-real-imag (mul (make-scheme-number -1) (real-part z)) (mul (make-scheme-number -1) (imag-part z)))) ;; interface to the rest of the system (define (tag x) (attach-tag 'rectangular x)) (put 'real-part '(rectangular) real-part) (put 'imag-part '(rectangular) imag-part) (put 'magnitude '(rectangular) magnitude) (put 'angle '(rectangular) angle) (put 'negate '(rectangular) (lambda (z) (tag (negate z)))) ;;(put 'project '(rectangular) ;; (lambda (z) (real-part z))) (put 'make-from-real-imag 'rectangular (lambda (x y) (tag (make-from-real-imag x y)))) (put 'make-from-mag-ang 'rectangular (lambda (r a) (tag (make-from-mag-ang r a)))) 'done) (define (install-polar-package) ;; internal procedures (define (magnitude z) (car z)) (define (angle z) (cdr z)) (define (make-from-mag-ang r a) (cons r a)) (define (real-part z) (mul (magnitude z) (cosine (angle z)))) (define (imag-part z) (mul (magnitude z) (sine (angle z)))) (define (make-from-real-imag x y) (cons (square-root (add (square x) (square y))) (arctan y x))) (define pi (make-scheme-number (* 2 (asin 1)))) (define (negate z) (make-from-mag-ang (magnitude z) (add pi (angle z)))) ;; interface to the rest of the system (define (tag x) (attach-tag 'polar x)) (put 'real-part '(polar) real-part) (put 'imag-part '(polar) imag-part) (put 'magnitude '(polar) magnitude) (put 'angle '(polar) angle) (put 'negate '(polar) (lambda (z) (tag (negate z)))) ;;(put 'project '(polar) ;;(lambda (z) real-part z)) (put 'make-from-real-imag 'polar (lambda (x y) (tag (make-from-real-imag x y)))) (put 'make-from-mag-ang 'polar (lambda (r a) (tag (make-from-mag-ang r a)))) 'done) (define (install-complex-package) ;; imported procedures from rectangular and polar packages (define (make-from-real-imag x y) ((get 'make-from-real-imag 'rectangular) x y)) (define (make-from-mag-ang r a) ((get 'make-from-mag-ang 'polar) r a)) ;; internal procedures (define (add-complex z1 z2) (make-from-real-imag (add (real-part z1) (real-part z2)) (add (imag-part z1) (imag-part z2)))) (define (sub-complex z1 z2) (make-from-real-imag (sub (real-part z1) (real-part z2)) (sub (imag-part z1) (imag-part z2)))) (define (mul-complex z1 z2) (make-from-mag-ang (mul (magnitude z1) (magnitude z2)) (add (angle z1) (angle z2)))) (define (div-complex z1 z2) (make-from-mag-ang (div (magnitude z1) (magnitude z2)) (sub (angle z1) (angle z2)))) ;; interface to rest of the system (define (tag z) (attach-tag 'complex z)) (put 'add '(complex complex) (lambda (z1 z2) (tag (add-complex z1 z2)))) (put 'add3 '(complex complex complex) (lambda (z1 z2 z3) (tag (add-complex z1 (add-complex z2 z3))))) (put 'sub '(complex complex) (lambda (z1 z2) (tag (sub-complex z1 z2)))) (put 'mul '(complex complex) (lambda (z1 z2) (tag (mul-complex z1 z2)))) (put 'div '(complex complex) (lambda (z1 z2) (tag (div-complex z1 z2)))) (put 'equ? '(complex complex) (lambda (z1 z2) (and (equ? (real-part z1) (real-part z2)) (equ? (imag-part z1) (imag-part z2))))) (put '=zero? '(complex) (lambda (z) (equ? (magnitude z) (make-scheme-number 0)))) ;;(put 'negate '(complex) ;;(lambda (z) (tag (negate z)))) (put 'negate '(complex) (lambda (z) (tag (make-from-real-imag (mul (real-part z) (make-scheme-number -1)) (mul (imag-part z) (make-scheme-number -1)))))) (put 'make-from-real-imag 'complex (lambda (x y) (tag (make-from-real-imag x y)))) (put 'make-from-mag-ang 'complex (lambda (r a) (tag (make-from-mag-ang r a)))) (put-coercion 'complex 'scheme-number (lambda (z) (real-part z))) 'done) ;; *incomplete* skeleton of package (define (install-polynomial-package) ;; internal procedures ;; representation of poly (define (make-poly variable term-list) (cons variable term-list)) (define (variable p) (car p)) (define (term-list p) (cdr p)) ;;[procedures same-variable? and variable? from section 2.3.2] (define (variable? x) (symbol? x)) (define (same-variable? v1 v2) (and (variable? v1) (variable? v2) (eq? v1 v2))) ;;(define (add-poly p1 p2) ... ) ;;[procedures used by add-poly] (define (add-poly p1 p2) (if (same-variable? (variable p1) (variable p2)) (make-poly (variable p1) (add (term-list p1) (term-list p2))) (error "Polys not in same var -- ADD-POLY" (list p1 p2)))) ;;(define (mul-poly p1 p2) ... ) ;;[procedures used by mul-poly] (define (mul-poly p1 p2) (if (same-variable? (variable p1) (variable p2)) (make-poly (variable p1) (mul (term-list p1) (term-list p2))) (error "Polys not in same var -- MUL-POLY" (list p1 p2)))) (define (div-poly p1 p2) (if (same-variable? (variable p1) (variable p2)) (let ((quotient-remainder (div (term-list p1) (term-list p2)))) (list (make-poly (variable p1) (car quotient-remainder)) (make-poly (variable p1) (cadr quotient-remainder)))) (error "Polys not in same var -- DIV-POLY" (list p1 p2)))) (define (gcd-poly p1 p2) (if (same-variable? (variable p1) (variable p2)) (make-poly (variable p1) (greatest-common-divisor (term-list p1) (term-list p2))))) (define (reduce-poly p1 p2) (let ((reduced-termlist (reduce (term-list p1) (term-list p2)))) (if (same-variable? (variable p1) (variable p2)) (list (make-poly (variable p1) (car reduced-termlist)) (make-poly (variable p1) (cadr reduced-termlist)))))) (define (negate-poly p) (make-poly (variable p) (negate (term-list p)))) (define (=zero-poly? p) (let ((terms (term-list p))) (if (null? terms) #t (and (= (coeff (first-term terms)) 0) (=zero-poly? (rest-terms terms)))))) ;; interface to rest of the system (define (tag p) (attach-tag 'polynomial p)) (put 'add '(polynomial polynomial) (lambda (p1 p2) (tag (add-poly p1 p2)))) (put 'sub '(polynomial polynomial) (lambda (p1 p2) (tag (add-poly p1 (negate-poly p2))))) (put 'mul '(polynomial polynomial) (lambda (p1 p2) (tag (mul-poly p1 p2)))) (put 'div '(polynomial polynomial) (lambda (p1 p2) (let ((quotient-remainder (div-poly p1 p2))) (list (tag (car quotient-remainder)) (tag (cadr quotient-remainder)))))) (put 'greatest-common-divisor '(polynomial polynomial) (lambda (p1 p2) (tag (gcd-poly p1 p2)))) (put 'reduce '(polynomial polynomial) (lambda (p1 p2) (let ((reduced (reduce-poly p1 p2))) (list (tag (car reduced)) (tag (cadr reduced)))))) (put 'negate '(polynomial) (lambda (p) (tag (negate-poly p)))) (put '=zero? '(polynomial) (lambda (p) (empty-termlist? (term-list p)))) (put 'make 'polynomial (lambda (var terms) (tag (make-poly var terms)))) 'done) (define (install-termlist-package) (define (tag l) (attach-tag 'termlist l)) (define (add-terms L1 L2) (cond ((empty-termlist? L1) L2) ((empty-termlist? L2) L1) (else (let ((t1 (first-term L1)) (t2 (first-term L2))) (cond ((> (order t1) (order t2)) (adjoin-term t1 (add-terms (rest-terms L1) L2))) ((< (order t1) (order t2)) (adjoin-term t2 (add-terms L1 (rest-terms L2)))) (else (adjoin-term (make-term (order t1) (add (coeff t1) (coeff t2))) (add-terms (rest-terms L1) (rest-terms L2))))))))) (define (sub-terms L1 L2) (add-terms L1 (negate L2))) (define (mul-terms L1 L2) (if (empty-termlist? L1) ((get 'the-empty-termlist (type-tag L2))) (add-terms (mul-term-by-all-terms (first-term L1) L2) (mul-terms (rest-terms L1) L2)))) (define (mul-term-by-all-terms t1 L) (if (empty-termlist? L) ((get 'the-empty-termlist (type-tag L))) (let ((t2 (first-term L))) (adjoin-term (make-term (+ (order t1) (order t2)) (mul (coeff t1) (coeff t2))) (mul-term-by-all-terms t1 (rest-terms L)))))) (define (div-terms L1 L2) (if (empty-termlist? L1) (list ((get 'the-empty-termlist (type-tag L1))) ((get 'the-empty-termlist (type-tag L2)))) (let ((t1 (first-term L1)) (t2 (first-term L2))) (if (> (order t2) (order t1)) (list ((get 'the-empty-termlist (type-tag L1))) L1) (let ((new-c (div (coeff t1) (coeff t2))) (new-o (- (order t1) (order t2)))) (let ((rest-of-result (div-terms (sub-terms L1 (mul-term-by-all-terms (make-term new-o new-c) L2)) L2))) ;compute rest of result recursively (cons (adjoin-term (make-term new-o new-c) (car rest-of-result)) (cdr rest-of-result)))))))) ;form complete result (define (remainder-terms L1 L2) (cadr (div-terms L1 L2))) (define (mul-terms-by-scalar termlist s) (mul-terms termlist (adjoin-term (make-term 0 s) ((get 'the-empty-termlist (type-tag termlist)))))) (define (div-terms-by-scalar termlist s) (mul-terms-by-scalar termlist (/ 1 s))) (define (pseudo-remainder-terms L1 L2) (let* ((c (coeff (first-term L2))) (o1 (order (first-term L1))) (o2 (order (first-term L2))) (i-factor (exp c (+ 1 (- o1 o2))))) ;; Only works for integer coefficients, so use non-generic (cadr (div-terms (mul-terms (adjoin-term (make-term 0 i-factor) ((get 'the-empty-termlist (type-tag L1)))) L1) L2)))) (define (coeff-gcd termlist) (if (empty-termlist? termlist) 0 (gcd (coeff (first-term termlist)) (coeff-gcd (rest-terms termlist))))) (define (gcd-terms a b) (if (empty-termlist? b) (div-terms-by-scalar a (coeff-gcd a)) (gcd-terms b (pseudo-remainder-terms a b)))) (define (reduce-terms n d) (let* ((term-gcd (gcd-terms n d)) (o1 (max (order n) (order d))) (o2 (order term-gcd)) (i-factor (exp (coeff (first-term term-gcd)) (+ 1 (- o1 o2))))) (list ;; Dividing by the gcd will give remainder zero, so we are only ;; interested in the quotient (car (div-terms (mul-terms-by-scalar n i-factor) term-gcd)) (car (div-terms (mul-terms-by-scalar d i-factor) term-gcd))))) ;; Constructors (put 'make-sparse-empty-termlist 'termlist (lambda () (tag ((get 'the-empty-termlist 'sparse))))) (put 'make-sparse-termlist 'termlist (lambda (term) (tag ((get 'make-from-term 'sparse) term)))) (put 'make-dense-empty-termlist 'termlist (lambda () (tag ((get 'the-empty-termlist 'dense))))) (put 'make-dense-termlist 'termlist (lambda (term) (tag ((get 'make-from-term 'dense) term)))) ;; Term will have its tag removed by apply-generic. This needs to be ;; re-added for the next apply-generic call (needed to step into the ;; appropriate termlist implementation). (put 'adjoin-term '(term termlist) (lambda (term termlist) (tag (adjoin-term (apply make-term term) termlist)))) ;; Selectors (put 'first-term '(termlist) first-term) (put 'rest-terms '(termlist) (lambda (termlist) (tag (rest-terms termlist)))) (put 'empty-termlist? '(termlist) empty-termlist?) ;; Operators (put 'add '(termlist termlist) (lambda (L1 L2) (tag (add-terms L1 L2)))) (put 'sub '(termlist termlist) (lambda (L1 L2) (tag (sub-terms L1 L2)))) (put 'mul '(termlist termlist) (lambda (L1 L2) (tag (mul-terms L1 L2)))) (put 'div '(termlist termlist) (lambda (L1 L2) (let ((quotient-remainder (div-terms L1 L2))) (list (tag (car quotient-remainder)) (tag (cdr quotient-remainder)))))) (put 'negate '(termlist) (lambda (L) (tag (negate L)))) (put 'greatest-common-divisor '(termlist termlist) (lambda (L1 L2) (tag (gcd-terms L1 L2)))) (put 'reduce '(termlist termlist) (lambda (L1 L2) (let ((reduced-termlist (reduce-terms L1 L2))) (list (tag (car reduced-termlist)) (tag (cadr reduced-termlist)))))) 'done) (define (install-sparse-package) ;; Make a termlist from a single term (define (make-termlist term) (list (contents term))) ;; representation of terms and term lists ;;[procedures adjoin-term ... coeff from text below] (define (adjoin-term term term-list) (if (=zero? (coeff term)) term-list (cons (contents term) term-list))) (define (negate-termlist term-list) (map (lambda (t) (list (car t) (negate (cadr t)))) term-list)) (define (the-empty-termlist) '()) (define (empty-termlist? l) (null? l)) (define (tag l) (attach-tag 'sparse l)) ;; Constructors (put 'make-from-term 'sparse (lambda (term) (tag (make-termlist term)))) (put 'the-empty-termlist 'sparse (lambda () (tag (the-empty-termlist)))) (put 'adjoin-term '(term sparse) (lambda (term termlist) (tag (adjoin-term (apply make-term term) termlist)))) ;; Selectors (put 'first-term '(sparse) (lambda (termlist) (if (pair? termlist) (make-term (caar termlist) (cadar termlist)) (make-term 0 0)))) (put 'rest-terms '(sparse) (lambda (termlist) (tag (cdr termlist)))) (put 'empty-termlist? '(sparse) empty-termlist?) (put 'order '(sparse) (lambda (termlist) (if (pair? termlist) (caar termlist) 0))) ;; Operators (put 'negate '(sparse) (lambda (termlist) (tag (negate-termlist termlist)))) 'done) (define (install-dense-package) (define (highest-order-term term-list) (- (length term-list) 1)) (define empty-termlist? null?) (define (adjoin-term term term-list) (define (zero-pad order term-list) (if (= order (highest-order-term term-list)) term-list (zero-pad order (cons 0 term-list)))) (define (strip-leading-zeros term-list) (cond ((null? term-list) '()) ((not (= (car term-list) 0)) term-list) (else strip-leading-zeros (cdr term-list)))) (let ((term-list-order (highest-order-term term-list))) (cond ((and (null? term-list) (= (order term) 0)) (list (coeff term))) ((= (coeff term) 0) (strip-leading-zeros term-list)) ((= (order term) (+ term-list-order 1)) (cons (coeff term) term-list)) (else (cons (coeff term) (zero-pad (- (order term) 1) term-list)))))) (define (negate terms) (map - terms)) (define (tag l) (attach-tag 'dense l)) ;; Constructors (put 'the-empty-termlist 'dense (lambda () (tag '()))) (put 'adjoin-term '(term dense) (lambda (term termlist) (tag (adjoin-term (apply make-term term) termlist)))) ;; Selectors (put 'first-term '(dense) (lambda (termlist) (make-term (highest-order-term termlist) (car termlist)))) (put 'rest-terms '(dense) (lambda (termlist) (tag (cdr termlist)))) (put 'empty-termlist? '(dense) empty-termlist?) (put 'order '(dense) highest-order-term) ;; Operators (put 'negate '(dense) (lambda (termlist) (tag (negate termlist)))) 'done) (define (install-term-package) (define (make-term order coeff) (tag (list order coeff))) (define (negate-term term) (make-term (order term) (negate (coeff term)))) (define (tag t) (attach-tag 'term t)) (put 'make 'term make-term) (put 'order '(term) car) (put 'coeff '(term) cadr) (put 'negate '(term) negate-term) 'done) ;; Generic constructors (define (make-scheme-number n) ((get 'make 'scheme-number) n)) (define (make-integer x) ((get 'make 'integer) x)) (define (make-rational n d) ((get 'make 'rational) n d)) (define (make-complex-from-real-imag x y) ((get 'make-from-real-imag 'complex) x y)) (define (make-complex-from-mag-ang r a) ((get 'make-from-mag-ang 'complex) r a)) (define (make-polynomial var terms) ((get 'make 'polynomial) var terms)) (define (make-term order coeff) ((get 'make 'term) order coeff)) (define (make-sparse-termlist sparse-terms) ((get 'make-sparse-termlist 'termlist) sparse-terms)) (define (make-sparse-empty-termlist) ((get 'make-sparse-empty-termlist 'termlist))) (define (make-dense-termlist dense-terms) ((get 'make-dense-termlist 'termlist) dense-terms)) (define (make-dense-empty-termlist) ((get 'make-dense-empty-termlist 'termlist))) ;; Generic selectors (define (real-part z) (apply-generic 'real-part z)) (define (imag-part z) (apply-generic 'imag-part z)) (define (magnitude z) (apply-generic 'magnitude z)) (define (angle z) (apply-generic 'angle z)) (define (order t) (apply-generic 'order t)) (define (coeff t) (apply-generic 'coeff t)) (put 'real-part '(complex) real-part) (put 'imag-part '(complex) imag-part) (put 'magnitude '(complex) magnitude) (put 'angle '(complex) angle) (define (first-term termlist) (apply-generic 'first-term termlist)) (define (rest-terms termlist) (apply-generic 'rest-terms termlist)) ;; Generic operators (define (add x y) (apply-generic 'add x y)) (define (add3 x y z) (apply-generic 'add3 x y z)) (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)) (define (sine x) (apply-generic 'sine x)) (define (cosine x) (apply-generic 'cosine x)) (define (square-root x) (apply-generic 'square-root x)) (define (arctan x y) (apply-generic 'arctan x y)) (define (negate x) (apply-generic 'negate x)) (define (square x) (mul x x)) (define (greatest-common-divisor a b) (apply-generic 'greatest-common-divisor a b)) (define (reduce a b) (apply-generic 'reduce a b)) (define (equ? x y) (apply-generic 'equ? x y)) ;;(put 'equ? '(complex complex) equ?) (define (=zero? x) (apply-generic '=zero? x)) (define (exp x y) (apply-generic 'exp x y)) (define (adjoin-term term termlist) (apply-generic 'adjoin-term term termlist)) (define (empty-termlist? termlist) (apply-generic 'empty-termlist? termlist)) (define (drop x) (and (type-tagged? x) (let ((p (project x))) (cond ((null? p) x) ((equ? x (raise p)) (drop p)) (else x))))) (install-scheme-number-package) (install-integer-package) (install-rational-package) (install-polar-package) (install-rectangular-package) (install-complex-package) (install-termlist-package) (install-sparse-package) (install-dense-package) (install-term-package) (install-polynomial-package) ;; Coercion (define (scheme-number->complex n) (make-complex-from-real-imag (contents n) 0)) (define (scheme-number->rational n) (make-rational n 1)) (define (scheme-number->scheme-number n) n) (define (complex->complex z) z) ;; 2.81a: If we call exp with two complex arguments, apply-generic fails to find an ;; operation with the correct argument list, so tries to coerce t1->t2. ;; b: If the arguments are of the same type, and if there isn't an operation defined for ;; that combination of arguments, then apply-generic will try to coerce a type to itself, ;; so there is a need change it. ;; 2.82: The approach of coercing to a common type would not work where there is a function ;; that takes mixed types. For example, if we have an operator to add a complex to a rational. ;; It isn't possible to coerce from one to the other, so a mixed-type operator is needed, and this ;; approach would fail. ;; 2.95 ;;(define p1 (make-polynomial 'x ;; (adjoin-term (make-term 2 1) ;; (adjoin-term (make-term 1 -2) ;; (adjoin-term (make-term 0 1) ;; (make-sparse-empty-termlist)))))) ;;(define p2 (make-polynomial 'x ;; (adjoin-term (make-term 2 11) ;; (adjoin-term (make-term 0 7) ;; (make-sparse-empty-termlist))))) ;;(define p3 (make-polynomial 'x (adjoin-term (make-term 1 13) ;; (adjoin-term (make-term 0 5) ;; (make-sparse-empty-termlist))))) ;;(define q1 (mul p1 p2)) ;;(define q2 (mul p1 p3)) ;; GCD of q1 and q2 is not p1: it is a polynomial with rational coefficients because ;; of the division of coefficients. ;; 2.97 (define p1 (make-polynomial 'x (adjoin-term (make-term 1 1) (adjoin-term (make-term 0 1) (make-sparse-empty-termlist))))) (define p2 (make-polynomial 'x (adjoin-term (make-term 3 1) (adjoin-term (make-term 0 -1) (make-sparse-empty-termlist))))) (define p3 (make-polynomial 'x (adjoin-term (make-term 1 1) (make-sparse-empty-termlist)))) (define p4 (make-polynomial 'x (adjoin-term (make-term 2 1) (adjoin-term (make-term 0 -1) (make-sparse-empty-termlist))))) (define rf1 (make-rational p1 p2)) (define rf2 (make-rational p3 p4))