sicp-ex-2.86



<< Previous exercise (2.85) | Index | Next exercise (2.87) >>


meteorgan

 (define (sine x) (apply-generic 'sine x)) 
 (define (cosine x) (apply-generic 'cosine x)) 
  
 ;; add into scheme-number package 
 (put 'sine 'scheme-number 
      (lambda (x) (tag (sin x)))) 
 (put 'cosine 'scheme-number 
      (lambda (x) (tag (cos x)))) 
  
 ;; add into rational package 
 (put 'sine 'rational 
      (lambda (x) (tag (sin x)))) 
 (put 'cosine 'rational 
      (lambda (x) (tag (cos x)))) 
  
 ;; To accomodate generic number in the complex package,  
 ;; we should replace operators such as + , * with theirs 
 ;; generic counterparts add, mul. 
 (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)))) 
  

I think it should be

 ;;; add into scheme-number package  
 (put 'sine 'rational (lambda (x) (sine (/ (numer x) (denom x)))))  
 (put 'cosine 'rational (lambda (x) (cosine (/ (numer x) (denom x))))) 


YZ

methods sine and cosine can only be defined on the scheme-number type, lower types have coercion int apply-generic. other methods like atan and expt(for the sqrt) should also be included, because the polar complex package need them.

 ;;; add into global 
 (define (sine x) (apply-generic 'sine x)) 
 (define (cosine x) (apply-generic 'cosine x)) 
 (define (arctan x) (apply-generic 'arctan x)) 
 (define (exp x y) (apply-generic 'exp x y)) 
  
 ;;; add into rational package  
   (put 'sine '(number) (lambda (x) (tag (sin x)))) 
   (put 'cosine '(number) (lambda (x) (tag (cos x)))) 
   (put 'arctan '(number) (lambda (x) (tag (atan x)))) 
   (put 'exp '(number number) (lambda (x y) (tag (expt x y)))) 
  
 ;;; complex-rect package  
   (define (square x) (mul x x)) 
   (define (sqrt x) (exp x 0.5)) 
   (define (make-from-mag-ang r a) (cons (mul r (cosine a)) (mul r (sine a)))) 
   (define (magnitude z) (sqrt (add (square (real-part z)) (square (imag-part z))))) 
   (define (angle z) (arctan (div (imag-part z) (real-part z)))) 
  
 ;;; complex-polar package  
   (define (real-part z) (mul (magnitude z) (cosine (angle z)))) 
   (define (imag-part z) (mul (magnitude z) (sine (angle z)))) 
  
 ;;; complex package  
 (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)))) 
  

Sphinxsky

My idea is to rewrite all basic operators to type operators through decorator, and to unify the input and output of all computing processes into scheme-number .

 ;; Converting data types to scheme-number 
 (define (install-type->scheme-number-package) 
     ;; real -> scheme-number 
     (put 'get-scheme-number '(real) 
         (lambda (x) (make-scheme-number x))) 
      
     ;; rational -> scheme-number 
     (put 'get-scheme-number '(rational) 
         (lambda (r) 
             (make-scheme-number 
                 (contents (div (numer r) (denom r)))))) 
      
     ;; scheme-number -> scheme-number 
     (put 'get-scheme-number '(scheme-number) 
         (lambda (x) (make-scheme-number x))) 
      
     'done) 
  
 ;; Conversion interface 
 (define (get-scheme-number x) 
     (apply-generic 'get-scheme-number x)) 
  
 ;; To rewrite basic operations into a form that can handle combined data 
 ;; Return the result as scheme-number 
 (define (decorator f) 
     ;; Unified input 
     (define (transform args) 
         (map 
             (lambda (arg) 
                 (if (number? arg) 
                     (make-scheme-number arg) 
                     (get-scheme-number arg))) 
             args)) 
      
     ;; Unified output 
     (lambda (first . other) 
         (make-scheme-number 
             (let ((args (map 
                             contents 
                             (transform (cons first other))))) 
                 (apply f args))))) 
  
 ;; To rewrite basic operations with decorator 
 ;; You can also write like this: 
 ;;     (set! + (decorator +)) 
 ;; So you don't have to change the code of complex package. 
 ;; But once you do that, the other packages will suffer. 
 (define new-square (decorator square)) 
 (define new-sqrt (decorator sqrt)) 
 (define new-add (decorator +)) 
 (define new-sub (decorator -)) 
 (define new-mul (decorator *)) 
 (define new-div (decorator /)) 
 (define sine (decorator sin)) 
 (define cosine (decorator cos)) 
 (define new-atan (decorator atan)) 
  

If you don't want to change any source code, write this:

  
  
  
  
 (define (decorator f) 
     (define (transform args) 
         (map 
             (lambda (arg) 
                 (if (number? arg) 
                     (make-scheme-number arg) 
                     (get-scheme-number arg))) 
             args)) 
      
     (lambda (first . other) 
         (let ((arg-seg (cons first other))) 
             (if (apply and (map number? arg-seg)) 
                 (apply f arg-seg) 
                 (make-scheme-number 
                     (apply f (map contents (transform arg-seg)))))))) 
  
 (define (operator-overload!) 
     (map 
         (lambda (f) 
             (set! f (decorator f))) 
         (list square sqrt + - * / sin cos atan)))