Advertisement
timothy235

sicp-2-5-2-combining-data-of-different-types

Mar 22nd, 2016
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 6.44 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;;;;;;;;;;
  4. ;; 2.81 ;;
  5. ;;;;;;;;;;
  6.  
  7. ;; a.  We would get an infinite loop.  Calling apply-generic would check if proc
  8. ;; was defined, see that it's not, coerce each argument to its own type, and then
  9. ;; re-enter apply-generic without ever hitting the error statement.
  10.  
  11. ;; b.  No, apply-generic works correctly as is.  It would needlessly look for
  12. ;; t1->t2 or t2->t1 in the coercion table before hitting the error statement, but
  13. ;; it would still correctly exit with an error.
  14.  
  15. ;; c.  Modify apply-generic so it does not try to coerce arguments of the same type.
  16.  
  17. (define (apply-generic op . args)
  18.   (define type-tags (map type-tag args))
  19.   (define proc (get op type-tags))
  20.   (cond [proc (apply proc (map contents args))]
  21.         [(= (length args) 2)
  22.          (define type1 (first type-tags))
  23.          (define type2 (second type-tags))
  24.          (cond [(not (eq? type1 type2))
  25.                 (define a1 (first args))
  26.                 (define a2 (second args))
  27.                 (define t1->t2 (get-coercion type1 type2))
  28.                 (define t2->t1 (get-coercion type2 type1))
  29.                 (cond [t1->t2 (apply-generic op (t1->t2 a1) a2)]
  30.                       [t2->t1 (apply-generic op a1 (t2->t1 a2))]
  31.                       [else (error "no method for these types"
  32.                                    (list op type-tags))])]
  33.                [else (error "no method for these types"
  34.                             (list op type-tags))])]
  35.         [else (error "no method for these types"
  36.                      (list op type-tags))]))
  37.  
  38. ;;;;;;;;;;
  39. ;; 2.82 ;;
  40. ;;;;;;;;;;
  41.  
  42. (define (all-same? symbols)
  43.   (or (< (length symbols) 2)
  44.       (andmap (lambda (s) (eq? s (first symbols)))
  45.               (rest symbols))))
  46.  
  47. (define (zip procs args)
  48.   (if (zero? (length procs))
  49.     empty
  50.     (cons ((first procs) (first args))
  51.           (zip (rest procs) (rest args)))))
  52.  
  53. ;; Try to coerce all args to first type, then second type, etc.
  54. ;; If possible, return coerced args, else return #f.
  55.  
  56. (define (coerce args)
  57.   (define type-tags (map type-tag args))
  58.   (define (loop i) ; coerce all args to type of argument i
  59.     (cond [(= i (length args)) #f]
  60.           [else
  61.             (define type (list-ref type-tags i))
  62.             (define procs
  63.               (map (lambda (t)
  64.                      (if (eq? t type)
  65.                       identity
  66.                        (get-coercion t type)))
  67.                    type-tags))
  68.             (if (not (member #f procs))
  69.               (zip procs args)
  70.               (loop (add1 i)))]))
  71.   (if (all-same? type-tags)
  72.     args
  73.     (loop 0)))
  74.  
  75. ;; This strategy could fail if the types of the arguments can not be coerced to
  76. ;; each others' types, but there might be another type, not present among the
  77. ;; arguments, that all could be coerced to.
  78.  
  79. ;;;;;;;;;;
  80. ;; 2.83 ;;
  81. ;;;;;;;;;;
  82.  
  83. ;; inside the integer package
  84. (define (raise-integer a) (make-rational a 1))
  85. (put-raise 'integer raise-integer)
  86.  
  87. ;; inside the rational numbers package
  88. (define (raise-rational q)
  89.   (make-real (/ (numer q) (denom q))))
  90. (put-raise 'rational raise-rational)
  91.  
  92. ;; inside the real numbers package
  93. (define (raise-real x) (make-complex-from-real-imag x 0))
  94. (put-raise 'real raise-real)
  95.  
  96. ;;;;;;;;;;
  97. ;; 2.84 ;;
  98. ;;;;;;;;;;
  99.  
  100. ;; only type-tower needs to change when adding more types
  101. (define type-tower '(integer rational real complex))
  102.  
  103. (define (index-of s symbols)
  104.   (define (loop i remaining)
  105.     (cond [(empty? remaining) #f]
  106.           [(eq? s (first remaining)) i]
  107.           [else (loop (add1 i) (rest remaining))]))
  108.   (loop 0 symbols))
  109.  
  110. (define (lower? type1 type2)
  111.   (< (index-of type1 type-tower)
  112.      (index-of type2 type-tower)))
  113.  
  114. (define (apply-generic op . args)
  115.   (define type-tags (map type-tag args))
  116.   (define proc (get op type-tags))
  117.   (cond [proc (apply proc (map contents args))]
  118.         [(= (length args) 2)
  119.          (define type1 (first type-tags))
  120.          (define type2 (second type-tags))
  121.          (define a1 (first args))
  122.          (define a2 (second args))
  123.          (cond [(lower? type1 type2) (apply-generic op (raise a1) a2)]
  124.                [(lower? type2 type1) (apply-generic op a1 (raise a2))]
  125.                [else (error "no method for these types"
  126.                             (list op type-tags))])]
  127.         [else (error "no method for these types"
  128.                      (list op type-tags))]))
  129.  
  130. ;;;;;;;;;;
  131. ;; 2.85 ;;
  132. ;;;;;;;;;;
  133.  
  134. ;; implementing project
  135.  
  136. ;; inside the rational numbers package
  137. (define (project-rational q)
  138.   (make-integer (floor (/ (numer q) (denom q)))))
  139. (put-project 'rational project-rational)
  140.  
  141. ;; inside the real numbers package
  142. (define (project-real x)
  143.   (make-rational (floor (* x 1000000)) 1000000))
  144. (put-project 'real project-real)
  145.  
  146. ;; inside the complex numbers package
  147. (define (project-complex z)
  148.   (make-real (re-part z)))
  149. (put-project 'complex project-complex)
  150.  
  151. (define (my-drop arg)
  152.   (define type (type-tag arg))
  153.   (define proc (get-project type))
  154.   (cond [proc
  155.           (define projected-arg (proc arg))
  156.           (if (equ? arg (raise projected-arg))
  157.             (my-drop projected-arg)
  158.             arg)]
  159.         [else arg]))
  160.  
  161. (define (apply-generic op . args)
  162.   (define type-tags (map type-tag args))
  163.   (define proc (get op type-tags))
  164.   (cond [proc (my-drop (apply proc (map contents args)))]
  165.         [(= (length args) 2)
  166.          (define type1 (first type-tags))
  167.          (define type2 (second type-tags))
  168.          (define a1 (first args))
  169.          (define a2 (second args))
  170.          (cond [(lower? type1 type2) (my-drop (apply-generic op (raise a1) a2))]
  171.                [(lower? type2 type1) (my-drop (apply-generic op a1 (raise a2)))]
  172.                [else (error "no method for these types"
  173.                             (list op type-tags))])]
  174.         [else (error "no method for these types"
  175.                      (list op type-tags))]))
  176.  
  177. ;;;;;;;;;;
  178. ;; 2.86 ;;
  179. ;;;;;;;;;;
  180.  
  181. (define (sine x) (apply-generic 'sine x))
  182. (define (cosine x) (apply-generic 'cosine x))
  183.  
  184. ;; The procedures inside the complex rectangular and complex polar packages would
  185. ;; need to be made generic.  We could no longer assume the components of a
  186. ;; complex number were real numbers.
  187.  
  188. ;; For example, the definition of make-from-mag-ang inside the complex rectangular
  189. ;; package would need to change from:
  190.  
  191. (define (make-from-mag-ang r a)
  192.   (list (* r (cos a)) (* r (sin a))))
  193.  
  194. ;; to:
  195.  
  196. (define (make-from-mag-ang r a)
  197.   (list (mul r (cosine a)) (mul r (sine a))))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement