timothy235 icon

sicp-2-5-1-generic-arithmetic-operations

timothy235 | PRO | 12/19/24 01:17:39 AM UTC (Edited) | 0 ⭐ | 4144 👁️ | Never ⏰ | []
Racket |

12.51 KB

|

None

|

0 👍

/

0 👎

#lang racket
 
;;; op table
 
(define op-table (make-hash))
(define (put op type item)
  (hash-set! op-table (list op type) item))
(define (get op type)
  (hash-ref op-table (list op type)))
 
;; I'm going to use lists instead of dotted pairs.
 
;;; generic operations
 
(define (attach-tag type-tag contents)
  (list type-tag contents))
(define (type-tag datum)
  (if (list? datum)
    (first datum)
    (error "bad tagged datum -- TYPE-TAG" datum)))
(define (contents datum)
  (if (list? datum)
    (second datum)
    (error "bad tagged datum -- CONTENTS" datum)))
(define (apply-generic op . args)
  (define type-tags (map type-tag args))
  (define proc (get op type-tags))
  (if proc
    (apply proc (map contents args))
    (error "no method for these types -- APPLY-GENERIC"
           (list op type-tags))))
 
(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))
(define (equ? x y) (apply-generic 'equ x y))
(define (=zero? x) (apply-generic '=zero x))
(define (re-part z) (apply-generic 're-part z))
(define (im-part z) (apply-generic 'im-part z))
(define (mag-part z) (apply-generic 'mag-part z))
(define (ang-part z) (apply-generic 'ang-part z))
 
;;; constructors
 
(define (make-scheme-number n)
  ((get 'make 'scheme-number) n))
(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))
 
;;; scheme numbers
 
(define (install-scheme-number-package)
  (define (tag x)
    (attach-tag 'scheme-number x))
  (put 'add '(scheme-number scheme-number)
       (lambda (x y) (tag (+ x y))))
  (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 'make 'scheme-number
       (lambda (x) (tag x)))
  (put 'equ '(scheme-number scheme-number)
       =)
  (put '=zero '(scheme-number)
       zero?)
  'done)
(install-scheme-number-package)
 
;;; rational numbers
 
(define (install-rational-package)
  ;; internal procedures
  (define (numer x) (first x))
  (define (denom x) (second x))
  (define (make-rat n d)
    (let ((g (gcd n d)))
      (list (/ n g) (/ d g))))
  (define (add-rat x y)
    (make-rat (+ (* (numer x) (denom y))
                 (* (numer y) (denom x)))
              (* (denom x) (denom y))))
  (define (sub-rat x y)
    (make-rat (- (* (numer x) (denom y))
                 (* (numer y) (denom x)))
              (* (denom x) (denom y))))
  (define (mul-rat x y)
    (make-rat (* (numer x) (numer y))
              (* (denom x) (denom y))))
  (define (div-rat x y)
    (make-rat (* (numer x) (denom y))
              (* (denom x) (numer y))))
  (define (equ? x y)
    (= (* (numer x) (denom y))
       (* (denom x) (numer y))))
  (define (=zero? x) (= (numer x) 0))
  ;; interface to the rest of the system
  (define (tag x) (attach-tag 'rational x))
  (put 'equ '(rational rational)
       (lambda (x y) (equ? x y)))
  (put '=zero '(rational)
       (lambda (x) (=zero? x)))
  (put 'add '(rational rational)
       (lambda (x y) (tag (add-rat x y))))
  (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 'make 'rational
       (lambda (n d) (tag (make-rat n d))))
  'done)
(install-rational-package)
 
;;; complex rectangular numbers
 
(define (install-rectangular-package)
  ;; internal procedures
  (define (re-part z) (first z))
  (define (im-part z) (second z))
  (define (make-from-real-imag x y) (list x y))
  (define (mag-part z)
    (sqrt (+ (sqr (re-part z))
             (sqr (im-part z)))))
  (define (ang-part z)
    (atan (im-part z) (re-part z)))
  (define (make-from-mag-ang r a)
    (list (* r (cos a)) (* r (sin a))))
  ;; interface to the rest of the system
  (define (tag x) (attach-tag 'rectangular x))
  (put 're-part '(rectangular) re-part)
  (put 'im-part '(rectangular) im-part)
  (put 'mag-part '(rectangular) mag-part)
  (put 'ang-part '(rectangular) ang-part)
  (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)
(install-rectangular-package)
 
;;; complex polar numbers
 
(define (install-polar-package)
  ;; internal procedures
  (define (mag-part z) (first z))
  (define (ang-part z) (second z))
  (define (make-from-mag-ang r a) (list r a))
  (define (re-part z)
    (* (mag-part z) (cos (ang-part z))))
  (define (im-part z)
    (* (mag-part z) (sin (ang-part z))))
  (define (make-from-real-imag x y)
    (list (sqrt (+ (sqr x) (sqr y)))
          (atan y x)))
  ;; interface to the rest of the system
  (define (tag x) (attach-tag 'polar x))
  (put 're-part '(polar) re-part)
  (put 'im-part '(polar) im-part)
  (put 'mag-part '(polar) mag-part)
  (put 'ang-part '(polar) ang-part)
  (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)
(install-polar-package)
 
;;; generic complex numbers
 
(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 (+ (re-part z1) (re-part z2))
                         (+ (im-part z1) (im-part z2))))
  (define (sub-complex z1 z2)
    (make-from-real-imag (- (re-part z1) (re-part z2))
                         (- (im-part z1) (im-part z2))))
  (define (mul-complex z1 z2)
    (make-from-mag-ang (* (mag-part z1) (mag-part z2))
                       (+ (ang-part z1) (ang-part z2))))
  (define (div-complex z1 z2)
    (make-from-mag-ang (/ (mag-part z1) (mag-part z2))
                       (- (ang-part z1) (ang-part z2))))
  (define (equ? z1 z2)
    ; account for round-off error
    (and
      (< (abs (- (re-part z1) (re-part z2))) 0.0001)
      (< (abs (- (im-part z1) (im-part z2))) 0.0001)))
  (define (=zero? z)
    (or (= (mag-part z) 0)
        ; account for round-off error
        (and (< (abs (re-part z)) 0.0001)
             (< (abs (im-part z)) 0.0001))))
  ;; interface to the rest of the system
  (put 're-part '(complex) re-part)
  (put 'im-part '(complex) im-part)
  (put 'mag-part '(complex) mag-part)
  (put 'ang-part '(complex) ang-part)
  (define (tag z) (attach-tag 'complex z))
  (put 'equ '(complex complex)
       (lambda (z1 z2) (equ? z1 z2)))
  (put '=zero '(complex)
       (lambda (z) (=zero? z)))
  (put 'add '(complex complex)
       (lambda (z1 z2) (tag (add-complex z1 z2))))
  (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 '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))))
  'done)
(install-complex-package)
 
(define q1 (make-rational 1 2))
(define q2 (make-rational 3 4))
(add q1 q2)
;; '(rational (5 4))
(sub q1 q2)
;; '(rational (-1 4))
(mul q1 q2)
;; '(rational (3 8))
(div q1 q2)
;; '(rational (2 3))
 
(define z1 (make-complex-from-real-imag 3 4))
(define z2 (make-complex-from-mag-ang 1 pi))
(add z1 z2)
;; '(complex (rectangular (2.0 4.0)))
(sub z1 z2)
;; '(complex (rectangular (4.0 4.0)))
(mul z1 z2)
;; '(complex (polar (5 4.068887871591405)))
(div z1 z2)
;; '(complex (polar (5 -2.214297435588181)))
 
;;;;;;;;;;
;; 2.77 ;;
;;;;;;;;;;
 
;; I'm using mag-part for magnitude so as not to conflict with the built-in racket
;; magnitude function.  To be consistent I'll also use ang-part instead of angle.
 
(define z '(complex (rectangular (3 4))))
 
;; without the added lines
 
;; (mag-part z)
;; ;; hash-ref: no value found for key
  ;; ;; key: '(mag-part (complex))
 
;; with the added lines
 
(mag-part z)
;; 5
 
;; In evaluating (mag-part z), apply-generic is called twice.  The first call
;; strips off the 'complex tag and dispatches to the generic mag-part again.  This
;; is because of the lines we added to the complex package.  The second call
;; strips off the 'rectangular tag and dispatches the mag-part procedure defined
;; in the rectangular package.
 
;; the manual trace
 
;; recall that (apply-generic op . args)
;; is (apply proc (map contents args))
;; where proc is (get op (map type-tag args))
 
;; (mag-part z)
;; (mag-part '(complex (rectangular (3 4))))
;; (apply-generic 'mag-part '(complex (rectangular (3 4))))
;; ;; this first call to apply-generic strips off the 'complex tag
;; (apply (get 'mag-part 'complex) '(rectangular (3 4)))
;; ;; the lines we added to the complex package say to use
;; ;; the generic mag-part again for (get 'mag-part 'complex)
;; (mag-part '(rectangular (3 4)))
;; (apply-generic 'mag-part '(rectangular (3 4)))
;; ;; this second call to apply-generic strips off the 'rectangular tag
;; ;; and uses the mag-part function defined in the complex rectangular package
;; (apply (get 'mag-part 'rectangular) '(3 4))
;; (apply (lambda (z) (sqrt (+ (sqr (re-part z)) (sqr (im-part z))))) '(3 4))
;; (sqrt (+ (sqr 3) (sqr 4)))
;; 5
 
;;;;;;;;;;
;; 2.78 ;;
;;;;;;;;;;
 
;; (define (attach-tag type-tag contents)
  ;; (if (number? contents)
    ;; contents
    ;; (list type-tag contents)))
 
;; (define (type-tag datum)
  ;; (cond [(number? datum) 'scheme-number]
        ;; [(list? datum) (first datum)]
        ;; [else (error "bad tagged datum -- TYPE-TAG" datum)]))
 
;; (define (contents datum)
  ;; (cond [(number? datum) datum]
        ;; [(list? datum) (second datum)]
        ;; [else (error "bad tagged datum -- CONTENTS" datum)]))
 
;;;;;;;;;;
;; 2.79 ;;
;;;;;;;;;;
 
;; Here is the code that was added above to implement equ?:
 
;; (define (equ? x y) (apply-generic 'equ x y))
;; ;; inside the scheme number package
;; (put 'equ '(scheme-number scheme-number)
     ;; =)
;; ;; inside the rational number package
;; (define (equ? x y)
  ;; (= (* (numer x) (denom y))
     ;; (* (denom x) (numer y))))
;; (put 'equ '(rational rational)
     ;; (lambda (x y) (equ? x y)))
;; ;; inside the generic complex number package
;; (define (equ? z1 z2)
  ;; ; account for round-off error
  ;; (and
    ;; (< (abs (- (re-part z1) (re-part z2))) 0.0001)
    ;; (< (abs (- (im-part z1) (im-part z2))) 0.0001)))
;; (put 'equ '(complex complex)
     ;; (lambda (z1 z2) (equ? z1 z2)))
 
(equ? (make-scheme-number 1)
      (make-scheme-number 1))
;; #t
(equ? (make-scheme-number 2)
      (make-scheme-number 3))
;; #f
(equ? (make-rational 1 2) (make-rational 3 6))
;; #t
(equ? (make-rational 1 2) (make-rational 2 3))
;; #f
(equ? (make-complex-from-real-imag -1 0)
      (make-complex-from-mag-ang 1 pi))
;; #t
(equ? (make-complex-from-real-imag 3 4)
      (make-complex-from-mag-ang 3 4))
;; #f
 
;;;;;;;;;;
;; 2.80 ;;
;;;;;;;;;;
 
;; Here is the code that was added above to implement =zero?:
 
;; (define (=zero? x) (apply-generic '=zero x))
;; ;; inside the scheme number package
;; (put '=zero '(scheme-number)
     ;; zero?)
;; ;; inside the rational number package
;; (define (=zero? x) (= (numer x) 0))
;; (put '=zero '(rational)
     ;; (lambda (x) (=zero? x)))
;; ;; inside the generic complex numbers package
;; (define (=zero? z)
  ;; (or (= (mag-part z) 0)
      ;; ; account for round-off error
      ;; (and (< (abs (re-part z)) 0.0001)
           ;; (< (abs (im-part z)) 0.0001))))
;; (put '=zero '(complex)
     ;; (lambda (z) (=zero? z)))
 
(=zero? (make-scheme-number 0))
;; #t
(=zero? (make-scheme-number 2))
;; #f
(=zero? (sub (make-rational 1 2)
             (make-rational 5 10)))
;; #t
(=zero? (sub (make-complex-from-real-imag 1 0)
             (make-complex-from-mag-ang 1 pi)))
;; #f
(=zero? (sub (make-complex-from-real-imag -1 0)
             (make-complex-from-mag-ang 1 pi)))
;; #t

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎