Advertisement
timothy235

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

Mar 11th, 2016
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 12.51 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;;; op table
  4.  
  5. (define op-table (make-hash))
  6. (define (put op type item)
  7.   (hash-set! op-table (list op type) item))
  8. (define (get op type)
  9.   (hash-ref op-table (list op type)))
  10.  
  11. ;; I'm going to use lists instead of dotted pairs.
  12.  
  13. ;;; generic operations
  14.  
  15. (define (attach-tag type-tag contents)
  16.   (list type-tag contents))
  17. (define (type-tag datum)
  18.   (if (list? datum)
  19.     (first datum)
  20.     (error "bad tagged datum -- TYPE-TAG" datum)))
  21. (define (contents datum)
  22.   (if (list? datum)
  23.     (second datum)
  24.     (error "bad tagged datum -- CONTENTS" datum)))
  25. (define (apply-generic op . args)
  26.   (define type-tags (map type-tag args))
  27.   (define proc (get op type-tags))
  28.   (if proc
  29.     (apply proc (map contents args))
  30.     (error "no method for these types -- APPLY-GENERIC"
  31.            (list op type-tags))))
  32.  
  33. (define (add x y) (apply-generic 'add x y))
  34. (define (sub x y) (apply-generic 'sub x y))
  35. (define (mul x y) (apply-generic 'mul x y))
  36. (define (div x y) (apply-generic 'div x y))
  37. (define (equ? x y) (apply-generic 'equ x y))
  38. (define (=zero? x) (apply-generic '=zero x))
  39. (define (re-part z) (apply-generic 're-part z))
  40. (define (im-part z) (apply-generic 'im-part z))
  41. (define (mag-part z) (apply-generic 'mag-part z))
  42. (define (ang-part z) (apply-generic 'ang-part z))
  43.  
  44. ;;; constructors
  45.  
  46. (define (make-scheme-number n)
  47.   ((get 'make 'scheme-number) n))
  48. (define (make-rational n d)
  49.   ((get 'make 'rational) n d))
  50. (define (make-complex-from-real-imag x y)
  51.   ((get 'make-from-real-imag 'complex) x y))
  52. (define (make-complex-from-mag-ang r a)
  53.   ((get 'make-from-mag-ang 'complex) r a))
  54.  
  55. ;;; scheme numbers
  56.  
  57. (define (install-scheme-number-package)
  58.   (define (tag x)
  59.     (attach-tag 'scheme-number x))
  60.   (put 'add '(scheme-number scheme-number)
  61.        (lambda (x y) (tag (+ x y))))
  62.   (put 'sub '(scheme-number scheme-number)
  63.        (lambda (x y) (tag (- x y))))
  64.   (put 'mul '(scheme-number scheme-number)
  65.        (lambda (x y) (tag (* x y))))
  66.   (put 'div '(scheme-number scheme-number)
  67.        (lambda (x y) (tag (/ x y))))
  68.   (put 'make 'scheme-number
  69.        (lambda (x) (tag x)))
  70.   (put 'equ '(scheme-number scheme-number)
  71.        =)
  72.   (put '=zero '(scheme-number)
  73.       zero?)
  74.   'done)
  75. (install-scheme-number-package)
  76.  
  77. ;;; rational numbers
  78.  
  79. (define (install-rational-package)
  80.   ;; internal procedures
  81.   (define (numer x) (first x))
  82.   (define (denom x) (second x))
  83.   (define (make-rat n d)
  84.     (let ((g (gcd n d)))
  85.       (list (/ n g) (/ d g))))
  86.   (define (add-rat x y)
  87.     (make-rat (+ (* (numer x) (denom y))
  88.                  (* (numer y) (denom x)))
  89.               (* (denom x) (denom y))))
  90.   (define (sub-rat x y)
  91.     (make-rat (- (* (numer x) (denom y))
  92.                  (* (numer y) (denom x)))
  93.               (* (denom x) (denom y))))
  94.   (define (mul-rat x y)
  95.     (make-rat (* (numer x) (numer y))
  96.               (* (denom x) (denom y))))
  97.   (define (div-rat x y)
  98.     (make-rat (* (numer x) (denom y))
  99.               (* (denom x) (numer y))))
  100.   (define (equ? x y)
  101.     (= (* (numer x) (denom y))
  102.        (* (denom x) (numer y))))
  103.   (define (=zero? x) (= (numer x) 0))
  104.   ;; interface to the rest of the system
  105.   (define (tag x) (attach-tag 'rational x))
  106.   (put 'equ '(rational rational)
  107.        (lambda (x y) (equ? x y)))
  108.   (put '=zero '(rational)
  109.        (lambda (x) (=zero? x)))
  110.   (put 'add '(rational rational)
  111.        (lambda (x y) (tag (add-rat x y))))
  112.   (put 'sub '(rational rational)
  113.        (lambda (x y) (tag (sub-rat x y))))
  114.   (put 'mul '(rational rational)
  115.        (lambda (x y) (tag (mul-rat x y))))
  116.   (put 'div '(rational rational)
  117.        (lambda (x y) (tag (div-rat x y))))
  118.   (put 'make 'rational
  119.        (lambda (n d) (tag (make-rat n d))))
  120.   'done)
  121. (install-rational-package)
  122.  
  123. ;;; complex rectangular numbers
  124.  
  125. (define (install-rectangular-package)
  126.   ;; internal procedures
  127.   (define (re-part z) (first z))
  128.   (define (im-part z) (second z))
  129.   (define (make-from-real-imag x y) (list x y))
  130.   (define (mag-part z)
  131.     (sqrt (+ (sqr (re-part z))
  132.              (sqr (im-part z)))))
  133.   (define (ang-part z)
  134.     (atan (im-part z) (re-part z)))
  135.   (define (make-from-mag-ang r a)
  136.     (list (* r (cos a)) (* r (sin a))))
  137.   ;; interface to the rest of the system
  138.   (define (tag x) (attach-tag 'rectangular x))
  139.   (put 're-part '(rectangular) re-part)
  140.   (put 'im-part '(rectangular) im-part)
  141.   (put 'mag-part '(rectangular) mag-part)
  142.   (put 'ang-part '(rectangular) ang-part)
  143.   (put 'make-from-real-imag 'rectangular
  144.        (lambda (x y) (tag (make-from-real-imag x y))))
  145.   (put 'make-from-mag-ang 'rectangular
  146.        (lambda (r a) (tag (make-from-mag-ang r a))))
  147.   'done)
  148. (install-rectangular-package)
  149.  
  150. ;;; complex polar numbers
  151.  
  152. (define (install-polar-package)
  153.   ;; internal procedures
  154.   (define (mag-part z) (first z))
  155.   (define (ang-part z) (second z))
  156.   (define (make-from-mag-ang r a) (list r a))
  157.   (define (re-part z)
  158.     (* (mag-part z) (cos (ang-part z))))
  159.   (define (im-part z)
  160.     (* (mag-part z) (sin (ang-part z))))
  161.   (define (make-from-real-imag x y)
  162.     (list (sqrt (+ (sqr x) (sqr y)))
  163.           (atan y x)))
  164.   ;; interface to the rest of the system
  165.   (define (tag x) (attach-tag 'polar x))
  166.   (put 're-part '(polar) re-part)
  167.   (put 'im-part '(polar) im-part)
  168.   (put 'mag-part '(polar) mag-part)
  169.   (put 'ang-part '(polar) ang-part)
  170.   (put 'make-from-real-imag 'polar
  171.        (lambda (x y) (tag (make-from-real-imag x y))))
  172.   (put 'make-from-mag-ang 'polar
  173.        (lambda (r a) (tag (make-from-mag-ang r a))))
  174.   'done)
  175. (install-polar-package)
  176.  
  177. ;;; generic complex numbers
  178.  
  179. (define (install-complex-package)
  180.   ;; imported procedures from rectangular and polar packages
  181.   (define (make-from-real-imag x y)
  182.     ((get 'make-from-real-imag 'rectangular) x y))
  183.   (define (make-from-mag-ang r a)
  184.     ((get 'make-from-mag-ang 'polar) r a))
  185.   ;; internal procedures
  186.   (define (add-complex z1 z2)
  187.     (make-from-real-imag (+ (re-part z1) (re-part z2))
  188.                          (+ (im-part z1) (im-part z2))))
  189.   (define (sub-complex z1 z2)
  190.     (make-from-real-imag (- (re-part z1) (re-part z2))
  191.                          (- (im-part z1) (im-part z2))))
  192.   (define (mul-complex z1 z2)
  193.     (make-from-mag-ang (* (mag-part z1) (mag-part z2))
  194.                        (+ (ang-part z1) (ang-part z2))))
  195.   (define (div-complex z1 z2)
  196.     (make-from-mag-ang (/ (mag-part z1) (mag-part z2))
  197.                        (- (ang-part z1) (ang-part z2))))
  198.   (define (equ? z1 z2)
  199.     ; account for round-off error
  200.     (and
  201.       (< (abs (- (re-part z1) (re-part z2))) 0.0001)
  202.       (< (abs (- (im-part z1) (im-part z2))) 0.0001)))
  203.   (define (=zero? z)
  204.     (or (= (mag-part z) 0)
  205.         ; account for round-off error
  206.         (and (< (abs (re-part z)) 0.0001)
  207.              (< (abs (im-part z)) 0.0001))))
  208.   ;; interface to the rest of the system
  209.   (put 're-part '(complex) re-part)
  210.   (put 'im-part '(complex) im-part)
  211.   (put 'mag-part '(complex) mag-part)
  212.   (put 'ang-part '(complex) ang-part)
  213.   (define (tag z) (attach-tag 'complex z))
  214.   (put 'equ '(complex complex)
  215.        (lambda (z1 z2) (equ? z1 z2)))
  216.   (put '=zero '(complex)
  217.        (lambda (z) (=zero? z)))
  218.   (put 'add '(complex complex)
  219.        (lambda (z1 z2) (tag (add-complex z1 z2))))
  220.   (put 'sub '(complex complex)
  221.        (lambda (z1 z2) (tag (sub-complex z1 z2))))
  222.   (put 'mul '(complex complex)
  223.        (lambda (z1 z2) (tag (mul-complex z1 z2))))
  224.   (put 'div '(complex complex)
  225.        (lambda (z1 z2) (tag (div-complex z1 z2))))
  226.   (put 'make-from-real-imag 'complex
  227.        (lambda (x y) (tag (make-from-real-imag x y))))
  228.   (put 'make-from-mag-ang 'complex
  229.        (lambda (r a) (tag (make-from-mag-ang r a))))
  230.   'done)
  231. (install-complex-package)
  232.  
  233. (define q1 (make-rational 1 2))
  234. (define q2 (make-rational 3 4))
  235. (add q1 q2)
  236. ;; '(rational (5 4))
  237. (sub q1 q2)
  238. ;; '(rational (-1 4))
  239. (mul q1 q2)
  240. ;; '(rational (3 8))
  241. (div q1 q2)
  242. ;; '(rational (2 3))
  243.  
  244. (define z1 (make-complex-from-real-imag 3 4))
  245. (define z2 (make-complex-from-mag-ang 1 pi))
  246. (add z1 z2)
  247. ;; '(complex (rectangular (2.0 4.0)))
  248. (sub z1 z2)
  249. ;; '(complex (rectangular (4.0 4.0)))
  250. (mul z1 z2)
  251. ;; '(complex (polar (5 4.068887871591405)))
  252. (div z1 z2)
  253. ;; '(complex (polar (5 -2.214297435588181)))
  254.  
  255. ;;;;;;;;;;
  256. ;; 2.77 ;;
  257. ;;;;;;;;;;
  258.  
  259. ;; I'm using mag-part for magnitude so as not to conflict with the built-in racket
  260. ;; magnitude function.  To be consistent I'll also use ang-part instead of angle.
  261.  
  262. (define z '(complex (rectangular (3 4))))
  263.  
  264. ;; without the added lines
  265.  
  266. ;; (mag-part z)
  267. ;; ;; hash-ref: no value found for key
  268.   ;; ;; key: '(mag-part (complex))
  269.  
  270. ;; with the added lines
  271.  
  272. (mag-part z)
  273. ;; 5
  274.  
  275. ;; In evaluating (mag-part z), apply-generic is called twice.  The first call
  276. ;; strips off the 'complex tag and dispatches to the generic mag-part again.  This
  277. ;; is because of the lines we added to the complex package.  The second call
  278. ;; strips off the 'rectangular tag and dispatches the mag-part procedure defined
  279. ;; in the rectangular package.
  280.  
  281. ;; the manual trace
  282.  
  283. ;; recall that (apply-generic op . args)
  284. ;; is (apply proc (map contents args))
  285. ;; where proc is (get op (map type-tag args))
  286.  
  287. ;; (mag-part z)
  288. ;; (mag-part '(complex (rectangular (3 4))))
  289. ;; (apply-generic 'mag-part '(complex (rectangular (3 4))))
  290. ;; ;; this first call to apply-generic strips off the 'complex tag
  291. ;; (apply (get 'mag-part 'complex) '(rectangular (3 4)))
  292. ;; ;; the lines we added to the complex package say to use
  293. ;; ;; the generic mag-part again for (get 'mag-part 'complex)
  294. ;; (mag-part '(rectangular (3 4)))
  295. ;; (apply-generic 'mag-part '(rectangular (3 4)))
  296. ;; ;; this second call to apply-generic strips off the 'rectangular tag
  297. ;; ;; and uses the mag-part function defined in the complex rectangular package
  298. ;; (apply (get 'mag-part 'rectangular) '(3 4))
  299. ;; (apply (lambda (z) (sqrt (+ (sqr (re-part z)) (sqr (im-part z))))) '(3 4))
  300. ;; (sqrt (+ (sqr 3) (sqr 4)))
  301. ;; 5
  302.  
  303. ;;;;;;;;;;
  304. ;; 2.78 ;;
  305. ;;;;;;;;;;
  306.  
  307. ;; (define (attach-tag type-tag contents)
  308.   ;; (if (number? contents)
  309.     ;; contents
  310.     ;; (list type-tag contents)))
  311.  
  312. ;; (define (type-tag datum)
  313.   ;; (cond [(number? datum) 'scheme-number]
  314.         ;; [(list? datum) (first datum)]
  315.         ;; [else (error "bad tagged datum -- TYPE-TAG" datum)]))
  316.  
  317. ;; (define (contents datum)
  318.   ;; (cond [(number? datum) datum]
  319.         ;; [(list? datum) (second datum)]
  320.         ;; [else (error "bad tagged datum -- CONTENTS" datum)]))
  321.  
  322. ;;;;;;;;;;
  323. ;; 2.79 ;;
  324. ;;;;;;;;;;
  325.  
  326. ;; Here is the code that was added above to implement equ?:
  327.  
  328. ;; (define (equ? x y) (apply-generic 'equ x y))
  329. ;; ;; inside the scheme number package
  330. ;; (put 'equ '(scheme-number scheme-number)
  331.      ;; =)
  332. ;; ;; inside the rational number package
  333. ;; (define (equ? x y)
  334.   ;; (= (* (numer x) (denom y))
  335.      ;; (* (denom x) (numer y))))
  336. ;; (put 'equ '(rational rational)
  337.      ;; (lambda (x y) (equ? x y)))
  338. ;; ;; inside the generic complex number package
  339. ;; (define (equ? z1 z2)
  340.   ;; ; account for round-off error
  341.   ;; (and
  342.     ;; (< (abs (- (re-part z1) (re-part z2))) 0.0001)
  343.     ;; (< (abs (- (im-part z1) (im-part z2))) 0.0001)))
  344. ;; (put 'equ '(complex complex)
  345.      ;; (lambda (z1 z2) (equ? z1 z2)))
  346.  
  347. (equ? (make-scheme-number 1)
  348.       (make-scheme-number 1))
  349. ;; #t
  350. (equ? (make-scheme-number 2)
  351.       (make-scheme-number 3))
  352. ;; #f
  353. (equ? (make-rational 1 2) (make-rational 3 6))
  354. ;; #t
  355. (equ? (make-rational 1 2) (make-rational 2 3))
  356. ;; #f
  357. (equ? (make-complex-from-real-imag -1 0)
  358.       (make-complex-from-mag-ang 1 pi))
  359. ;; #t
  360. (equ? (make-complex-from-real-imag 3 4)
  361.       (make-complex-from-mag-ang 3 4))
  362. ;; #f
  363.  
  364. ;;;;;;;;;;
  365. ;; 2.80 ;;
  366. ;;;;;;;;;;
  367.  
  368. ;; Here is the code that was added above to implement =zero?:
  369.  
  370. ;; (define (=zero? x) (apply-generic '=zero x))
  371. ;; ;; inside the scheme number package
  372. ;; (put '=zero '(scheme-number)
  373.      ;; zero?)
  374. ;; ;; inside the rational number package
  375. ;; (define (=zero? x) (= (numer x) 0))
  376. ;; (put '=zero '(rational)
  377.      ;; (lambda (x) (=zero? x)))
  378. ;; ;; inside the generic complex numbers package
  379. ;; (define (=zero? z)
  380.   ;; (or (= (mag-part z) 0)
  381.       ;; ; account for round-off error
  382.       ;; (and (< (abs (re-part z)) 0.0001)
  383.            ;; (< (abs (im-part z)) 0.0001))))
  384. ;; (put '=zero '(complex)
  385.      ;; (lambda (z) (=zero? z)))
  386.  
  387. (=zero? (make-scheme-number 0))
  388. ;; #t
  389. (=zero? (make-scheme-number 2))
  390. ;; #f
  391. (=zero? (sub (make-rational 1 2)
  392.              (make-rational 5 10)))
  393. ;; #t
  394. (=zero? (sub (make-complex-from-real-imag 1 0)
  395.              (make-complex-from-mag-ang 1 pi)))
  396. ;; #f
  397. (=zero? (sub (make-complex-from-real-imag -1 0)
  398.              (make-complex-from-mag-ang 1 pi)))
  399. ;; #t
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement