Advertisement
timothy235

sicp-2-5-2-the-generic-arithmetic-program

Mar 22nd, 2016
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 15.00 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;;;;;;;;;;;
  4. ;; NOTES ;;
  5. ;;;;;;;;;;;
  6.  
  7. ;; The generic arithmetic program through exercise 2.86, using type coercion, type
  8. ;; simplification, and generic components for complex numbers.
  9.  
  10. ;; Note that integers are represented as un-tagged Racket exact integers like 1,
  11. ;; and reals are represented as un-tagged Racket inexact numbers like 1.0.
  12.  
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14. ;; OP, RAISE, AND PROJECT TABLES ;;
  15. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  16.  
  17. (define op-table (make-hash))
  18. (define (put op tag-list procedure) (hash-set! op-table (list op tag-list) procedure))
  19. (define (can-apply? op tag-list) (member (list op tag-list) (hash-keys op-table)))
  20. (define (get op tag-list) (hash-ref op-table (list op tag-list)))
  21.  
  22. (define project-table (make-hash))
  23. (define (put-project type procedure) (hash-set! project-table type procedure))
  24. (define (can-project? arg) (member (type-tag arg) (hash-keys project-table)))
  25. (define (project arg) ((hash-ref project-table (type-tag arg)) arg))
  26.  
  27. (define raise-table (make-hash))
  28. (define (put-raise type procedure) (hash-set! raise-table type procedure))
  29. (define (can-raise? arg) (member (type-tag arg) (hash-keys raise-table)))
  30. (define (raise arg) ((hash-ref raise-table (type-tag arg)) arg))
  31.  
  32. ;;;;;;;;;;;;;;;;;;;;;;;;
  33. ;; GENERIC OPERATIONS ;;
  34. ;;;;;;;;;;;;;;;;;;;;;;;;
  35.  
  36. (define (attach-tag type-tag contents)
  37.   (cond [(exact-integer? contents) contents]
  38.         [(inexact-real? contents) contents]
  39.         [else (list type-tag contents)]))
  40.  
  41. (define (type-tag datum)
  42.   (cond [(exact-integer? datum) 'integer]
  43.         [(inexact-real? datum) 'real]
  44.         [(pair? datum) (first datum)]
  45.         [else (error "bad tagged-datum -- TYPE-TAG" datum)]))
  46.  
  47. (define (contents datum)
  48.   (cond [(exact-integer? datum) datum]
  49.         [(inexact-real? datum) datum]
  50.         [(pair? datum) (second datum)]
  51.         [else (error "bad tagged datum -- CONTENTS" datum)]))
  52.  
  53. (define (simplify arg)
  54.   (cond [(can-project? arg)
  55.          (define projected-arg (project arg))
  56.          (if (equ? arg (raise projected-arg))
  57.            (simplify projected-arg)
  58.            arg)]
  59.         [else arg]))
  60.  
  61. (define (highest-type tag-list)
  62.   ;; Raise 0 through all the types.  Keep the highest type found in tag-list.
  63.   (define (loop type arg)
  64.     (cond [(can-raise? arg)
  65.            (define new-arg (raise arg))
  66.            (define new-type (type-tag new-arg))
  67.            (if (member new-type tag-list)
  68.              (loop new-type new-arg)
  69.              (loop type new-arg))]
  70.           [else type]))
  71.   (loop 'integer 0))
  72.  
  73. (define (coerce args target-type)
  74.   (define (coerce-one arg)
  75.     (if (eq? (type-tag arg) target-type)
  76.       arg
  77.       (coerce-one (raise arg))))
  78.   (map coerce-one args))
  79.  
  80. (define (all-same? symbols)
  81.   (or (< (length symbols) 2)
  82.       (andmap (lambda (s) (eq? s (first symbols)))
  83.               (rest symbols))))
  84.  
  85. (define (apply-generic op . args)
  86.   (define type-tags (map type-tag args))
  87.   (cond [(can-apply? op type-tags)
  88.          (apply (get op type-tags) (map contents args))]
  89.         [(not (all-same? type-tags))
  90.          (define new-args (coerce args (highest-type type-tags)))
  91.          (apply apply-generic (cons op new-args))]
  92.         [else (error "no method for this op -- APPLY-GENERIC" op)]))
  93.  
  94. ;; Only simplify the numerical operations and the complex selectors.
  95. ;; Do not simplify predicates or constructors.
  96.  
  97. ;; arithmetic
  98. (define (add x y) (simplify (apply-generic 'add x y)))
  99. (define (sub x y) (simplify (apply-generic 'sub x y)))
  100. (define (mul x y) (simplify (apply-generic 'mul x y)))
  101. (define (div x y) (simplify (apply-generic 'div x y)))
  102. ;; predicates
  103. (define (=zero? x) (apply-generic '=zero? x))
  104. (define (equ? x y) (apply-generic 'equ? x y))
  105. ;; complex number selectors
  106. (define (re-part z) (simplify (apply-generic 're-part z)))
  107. (define (im-part z) (simplify (apply-generic 'im-part z)))
  108. (define (mag-part z) (simplify (apply-generic 'mag-part z)))
  109. (define (ang-part z) (simplify (apply-generic 'ang-part z)))
  110. ;; numerical operations needed for generic complex number components
  111. (define (absolute x) (apply-generic 'absolute x))
  112. (define (expo x y) (simplify (apply-generic 'expo x y)))
  113. (define (arctan y x) (simplify (apply-generic 'arctan y x)))
  114. (define (cosine x) (simplify (apply-generic 'cosine x)))
  115. (define (sine x) (simplify (apply-generic 'sine x)))
  116. (define (square x) (simplify (apply-generic 'square x)))
  117. (define (square-root x) (simplify (apply-generic 'square-root x)))
  118. ;; constructors
  119. (define (make-integer a) ((get 'make 'integer) a))
  120. (define (make-rational n d) ((get 'make 'rational) n d))
  121. (define (make-real x) ((get 'make 'real) x))
  122. (define (make-complex-from-real-imag x y) ((get 'make-from-real-imag 'complex) x y))
  123. (define (make-complex-from-mag-ang r a) ((get 'make-from-mag-ang 'complex) r a))
  124.  
  125. ;; Note that we cannot simply define make-integer as (get 'make 'integer)
  126. ;; because that procedure has not been stored in the op-table yet.
  127.  
  128. ;;;;;;;;;;;;;;
  129. ;; INTEGERS ;;
  130. ;;;;;;;;;;;;;;
  131.  
  132. (define (install-integer-package)
  133.   ;; internal procedures
  134.   (define (make-integer a)
  135.     (define flr (floor a))
  136.     (if (exact? flr) flr (inexact->exact flr)))
  137.   (define (arctan-int b a) (make-real (atan b a)))
  138.   (define (cosine-int a) (make-real (cos a)))
  139.   (define (sine-int a) (make-real (sin a)))
  140.   (define (square-root-int a) (make-real (sqrt a)))
  141.   (define (raise-int datum)
  142.     (define a (contents datum))
  143.     (make-rational a 1))
  144.   ;; interface to the rest of the system
  145.   (put '=zero? '(integer) zero?)
  146.   (put 'absolute '(integer) abs)
  147.   (put 'add '(integer integer) +)
  148.   (put 'arctan '(integer integer) arctan-int)
  149.   (put 'cosine '(integer) cosine-int)
  150.   (put 'div '(integer integer) make-rational)
  151.   (put 'equ? '(integer integer) =)
  152.   (put 'expo '(integer integer) expt)
  153.   (put 'make 'integer make-integer)
  154.   (put 'mul '(integer integer) *)
  155.   (put 'sine '(integer) sine-int)
  156.   (put 'square-root '(integer) square-root-int)
  157.   (put 'square '(integer) sqr)
  158.   (put 'sub '(integer integer) -)
  159.   (put-raise 'integer raise-int)
  160.   'done-installing-integers)
  161. (install-integer-package)
  162.  
  163. ;;;;;;;;;;;;;;;;;;;;;;
  164. ;; RATIONAL NUMBERS ;;
  165. ;;;;;;;;;;;;;;;;;;;;;;
  166.  
  167. (define (install-rational-package)
  168.   ;; internal procedures
  169.   (define (make-rat n d)
  170.     (let ([g (gcd n d)])
  171.       (list (make-integer (/ n g)) (make-integer (/ d g)))))
  172.   (define (numer x) (first x))
  173.   (define (denom x) (second x))
  174.   (define (=zero-rat? x) (zero? (numer x)))
  175.   (define (equ-rat? x y)
  176.     (= (* (numer x) (denom y))
  177.        (* (denom x) (numer y))))
  178.   (define (absolute-rat x) (make-real (abs (/ (numer x) (denom x)))))
  179.   (define (add-rat x y)
  180.     (make-rat (+ (* (numer x) (denom y))
  181.                  (* (numer y) (denom x)))
  182.               (* (denom x) (denom y))))
  183.   (define (sub-rat x y)
  184.     (make-rat (- (* (numer x) (denom y))
  185.                  (* (numer y) (denom x)))
  186.               (* (denom x) (denom y))))
  187.   (define (mul-rat x y)
  188.     (make-rat (* (numer x) (numer y))
  189.               (* (denom x) (denom y))))
  190.   (define (div-rat x y)
  191.     (make-rat (* (numer x) (denom y))
  192.               (* (denom x) (numer y))))
  193.   (define (expo-rat x y) (make-real (expt (/ (* (numer x) 1.0) (denom x))
  194.                                           (/ (* (numer y) 1.0) (denom y)))))
  195.   (define (arctan-rat y x) (make-real (atan (/ (numer y) (denom y))
  196.                                             (/ (numer x) (denom x)))))
  197.   (define (cosine-rat x) (make-real (cos (/ (numer x) (denom x)))))
  198.   (define (sine-rat x) (make-real (sin (/ (numer x) (denom x)))))
  199.   (define (square-root-rat x) (make-real (sqrt (/ (numer x) (denom x)))))
  200.   (define (square-rat x) (make-rat (sqr (numer x)) (sqr (denom x))))
  201.   (define (project-rat datum)
  202.     (define x (contents datum))
  203.     (make-integer (floor (/ (numer x) (denom x)))))
  204.   (define (raise-rat datum)
  205.     (define x (contents datum))
  206.     (make-real (/ (numer x) (denom x))))
  207.   ;; interface to the rest of the system
  208.   (define (tag x) (attach-tag 'rational x))
  209.   (put 'make 'rational (compose tag make-rat))
  210.   (put '=zero? '(rational) =zero-rat?)
  211.   (put 'equ? '(rational rational) equ-rat?)
  212.   (put 'absolute '(rational) absolute-rat)
  213.   (put 'add '(rational rational) (compose tag add-rat))
  214.   (put 'sub '(rational rational) (compose tag sub-rat))
  215.   (put 'mul '(rational rational) (compose tag mul-rat))
  216.   (put 'div '(rational rational) (compose tag div-rat))
  217.   (put 'expo '(rational rational) expo-rat)
  218.   (put 'arctan '(rational rational) arctan-rat)
  219.   (put 'cosine '(rational) cosine-rat)
  220.   (put 'sine '(rational) sine-rat)
  221.   (put 'square-root '(rational) square-root-rat)
  222.   (put 'square '(rational) (compose tag square-rat))
  223.   (put-project 'rational project-rat)
  224.   (put-raise 'rational raise-rat)
  225.   'done-installing-rationals)
  226. (install-rational-package)
  227.  
  228. ;;;;;;;;;;;;;;;;;;
  229. ;; REAL NUMBERS ;;
  230. ;;;;;;;;;;;;;;;;;;
  231.  
  232. (define (install-real-package)
  233.   ;; internal procedures
  234.   (define (make-real x) (if (inexact? x) x (exact->inexact x)))
  235.   (define (project-real datum)
  236.     (define x (contents datum))
  237.     (make-rational (floor (* x 1000000)) 1000000))
  238.   (define (raise-real datum)
  239.     (define x (contents datum))
  240.     (make-complex-from-real-imag x 0))
  241.   ;; interface to the rest of the system
  242.   (put '=zero? '(real) zero?)
  243.   (put 'absolute '(real) abs)
  244.   (put 'add '(real real) +)
  245.   (put 'arctan '(real real) atan)
  246.   (put 'cosine '(real) cos)
  247.   (put 'div '(real real) /)
  248.   (put 'equ? '(real real) =)
  249.   (put 'expo '(real real) expt)
  250.   (put 'make 'real make-real)
  251.   (put 'mul '(real real) *)
  252.   (put 'sine '(real) sin)
  253.   (put 'square-root '(real) sqrt)
  254.   (put 'square '(real) sqr)
  255.   (put 'sub '(real real) -)
  256.   (put-project 'real project-real)
  257.   (put-raise 'real raise-real)
  258.   'done-installing-reals)
  259. (install-real-package)
  260.  
  261. ;;;;;;;;;;;;;;;;;;;;;
  262. ;; COMPLEX NUMBERS ;;
  263. ;;;;;;;;;;;;;;;;;;;;;
  264.  
  265. (define (install-complex-package)
  266.  
  267.   ;;; rectangular complex numbers
  268.   (define (install-rectangular-package)
  269.     ;; internal procedures
  270.     (define (make-from-real-imag-rect x y) (list x y))
  271.     (define (re-part-rect z) (first z))
  272.     (define (im-part-rect z) (second z))
  273.     (define (make-from-mag-ang-rect r a)
  274.       (list (mul r (cosine a))
  275.             (mul r (sine a))))
  276.     (define (mag-part-rect z)
  277.       (square-root (add (square (re-part-rect z))
  278.                         (square (im-part-rect z)))))
  279.     (define (ang-part-rect z)
  280.       (arctan (im-part-rect z) (re-part-rect z)))
  281.     ;; interface to the rest of the system
  282.     (define (tag z) (attach-tag 'rectangular z))
  283.     (put 're-part '(rectangular) re-part-rect)
  284.     (put 'im-part '(rectangular) im-part-rect)
  285.     (put 'mag-part '(rectangular) mag-part-rect)
  286.     (put 'ang-part '(rectangular) ang-part-rect)
  287.     (put 'make-from-real-imag 'rectangular (compose tag make-from-real-imag-rect))
  288.     (put 'make-from-mag-ang 'rectangular (compose tag make-from-mag-ang-rect))
  289.     'done)
  290.   (install-rectangular-package)
  291.  
  292.   ;;; polar complex numbers
  293.   (define (install-polar-package)
  294.     ;; internal procedures
  295.     (define (make-from-mag-ang-polar r a) (list r a))
  296.     (define (mag-part-polar z) (first z))
  297.     (define (ang-part-polar z) (second z))
  298.     (define (make-from-real-imag-polar x y)
  299.       (list (square-root (add (square x) (square y)))
  300.             (arctan y x)))
  301.     (define (re-part-polar z)
  302.       (mul (mag-part-polar z) (cosine (ang-part-polar z))))
  303.     (define (im-part-polar z)
  304.       (mul (mag-part-polar z) (sine (ang-part-polar z))))
  305.     ;; interface to the rest of the system
  306.     (define (tag x) (attach-tag 'polar x))
  307.     (put 're-part '(polar) re-part-polar)
  308.     (put 'im-part '(polar) im-part-polar)
  309.     (put 'mag-part '(polar) mag-part-polar)
  310.     (put 'ang-part '(polar) ang-part-polar)
  311.     (put 'make-from-real-imag 'polar (compose tag make-from-real-imag-polar))
  312.     (put 'make-from-mag-ang 'polar (compose tag make-from-mag-ang-polar))
  313.     'done)
  314.   (install-polar-package)
  315.  
  316.   ;;; generic complex numbers
  317.   ;; internal procedures
  318.   ; constructors
  319.   (define (make-from-real-imag x y)
  320.     ((get 'make-from-real-imag 'rectangular) x y))
  321.   (define (make-from-mag-ang r a)
  322.     ((get 'make-from-mag-ang 'polar) r a))
  323.   ; predicates
  324.   (define (equ-complex? z1 z2)
  325.     (and (< (absolute (sub (re-part z1) (re-part z2))) 0.000001)
  326.          (< (absolute (sub (im-part z1) (im-part z2))) 0.000001)))
  327.   (define (=zero-complex? z)
  328.     (or (=zero? (mag-part z))
  329.         (and (< (absolute (re-part z)) 0.000001)
  330.              (< (absolute (im-part z)) 0.000001))))
  331.   ; arithmetic
  332.   (define (add-complex z1 z2)
  333.     (make-from-real-imag (add (re-part z1) (re-part z2))
  334.                          (add (im-part z1) (im-part z2))))
  335.   (define (sub-complex z1 z2)
  336.     (make-from-real-imag (sub (re-part z1) (re-part z2))
  337.                          (sub (im-part z1) (im-part z2))))
  338.   (define (mul-complex z1 z2)
  339.     (make-from-mag-ang (mul (mag-part z1) (mag-part z2))
  340.                        (add (ang-part z1) (ang-part z2))))
  341.   (define (div-complex z1 z2)
  342.     (make-from-mag-ang (div (mag-part z1) (mag-part z2))
  343.                        (sub (ang-part z1) (ang-part z2))))
  344.   (define (expo-complex z1 z2)
  345.     (define w (expt (+ (make-real (re-part z1))
  346.                        (* (make-real (im-part z1)) 0+i))
  347.                     (+ (make-real (re-part z2))
  348.                        (* (make-real (im-part z2)) 0+i))))
  349.     (make-from-real-imag (real-part w) (imag-part w)))
  350.   (define (project-complex datum)
  351.     (define z (contents datum))
  352.     (make-real (re-part z)))
  353.   ;; interface to the rest of the system
  354.   (define (tag z) (attach-tag 'complex z))
  355.   (put 'make-from-real-imag 'complex (compose tag make-from-real-imag))
  356.   (put 'make-from-mag-ang 'complex (compose tag make-from-mag-ang))
  357.   (put '=zero? '(complex) =zero-complex?)
  358.   (put 'equ? '(complex complex) equ-complex?)
  359.   (put 're-part '(complex) re-part)
  360.   (put 'im-part '(complex) im-part)
  361.   (put 'mag-part '(complex) mag-part)
  362.   (put 'ang-part '(complex) ang-part)
  363.   (put 'add '(complex complex) (compose tag add-complex))
  364.   (put 'sub '(complex complex) (compose tag sub-complex))
  365.   (put 'mul '(complex complex) (compose tag mul-complex))
  366.   (put 'div '(complex complex) (compose tag div-complex))
  367.   (put 'expo '(complex complex) (compose tag expo-complex))
  368.   (put-project 'complex project-complex)
  369.   'done-installing-complex-numbers)
  370. (install-complex-package)
  371.  
  372. ;;;;;;;;;;;
  373. ;; TESTS ;;
  374. ;;;;;;;;;;;
  375.  
  376. (define q1 (make-rational 1 2))
  377. (define q2 (make-rational 3 4))
  378. (add q1 q2)
  379. ;; '(rational (5 4))
  380. (sub q1 q2)
  381. ;; '(rational (-1 4))
  382. (mul q1 q2)
  383. ;; '(rational (3 8))
  384. (div q1 q2)
  385. ;; '(rational (2 3))
  386.  
  387. (define z1 (make-complex-from-real-imag 3 4))
  388. (define z2 (make-complex-from-mag-ang 1 pi))
  389. (add z1 z2)
  390. ;; '(complex (rectangular (2 4)))
  391. (sub z1 z2)
  392. ;; '(complex (rectangular (4 4)))
  393. (mul z1 z2)
  394. ;; '(complex (polar (5 4.068887871591405)))
  395. (div z1 z2)
  396. ;; '(complex (polar (5 -2.214297435588181)))
  397.  
  398. (define w (make-complex-from-real-imag 0.5 (make-rational 3 4)))
  399. (re-part w)
  400. ;; '(rational (1 2))
  401. (im-part w)
  402. ;; '(rational (3 4))
  403. (=zero? (sub w (make-complex-from-real-imag (make-rational 1 2) 0.75)))
  404. ;; #t
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement