timothy235

sicp-2-4-multiple-representations-for-abstract-data

Mar 10th, 2016
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 5.66 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;;;;;;;;;;
  4. ;; 2.73 ;;
  5. ;;;;;;;;;;
  6.  
  7. (define deriv-table (make-hash))
  8. (define (put type item) (hash-set! deriv-table type item))
  9. (define (get type) (hash-ref deriv-table type))
  10.  
  11. (define (=number? x y) (and (number? x) (number? y) (= x y)))
  12. (define (variable? x) (symbol? x))
  13. (define (same-variable? v1 v2)
  14.   (and (variable? v1) (variable? v2) (eq? v1 v2)))
  15. (define (operator expr) (first expr))
  16. (define (operands expr) (rest expr))
  17.  
  18. (define (deriv expr var)
  19.   (cond [(number? expr) 0]
  20.         [(variable? expr) (if (same-variable? expr var) 1 0)]
  21.         [else ((get (operator expr)) (operands expr) var)]))
  22.  
  23. ;; a.  number? and same-variable? cannot be put in the op table because they do
  24. ;; not operate on tagged expressions.
  25.  
  26. ;; constructors and selectors
  27. (define (make-sum a1 a2)
  28.   (cond [(=number? a1 0) a2]
  29.         [(=number? a2 0) a1]
  30.         [(and (number? a1) (number? a2)) (+ a1 a2)]
  31.         [else (list '+ a1 a2)]))
  32. (define (addend s) (first s))
  33. (define (augend s) (second s))
  34. (define (make-product m1 m2)
  35.   (cond [(or (=number? m1 0) (=number? m2 0)) 0]
  36.         [(=number? m1 1) m2]
  37.         [(=number? m2 1) m1]
  38.         [(and (number? m1) (number? m2)) (* m1 m2)]
  39.         [else (list '* m1 m2)]))
  40. (define (multiplier p) (first p))
  41. (define (multiplicand p) (second p))
  42. (define (make-exponentiation base expo)
  43.   (cond [(=number? expo 0) 1]
  44.         [(=number? expo 1) base]
  45.         [(and (number? base) (number? expo)) (expt base expo)]
  46.         [else (list '** base expo)]))
  47. (define (base e) (first e))
  48. (define (exponent e) (second e))
  49.  
  50. (define (install-differentiation-rules)
  51.   (define (sum-rule expr var)
  52.     (make-sum (deriv (addend expr) var)
  53.               (deriv (augend expr) var)))
  54.   (define (product-rule expr var)
  55.     (make-sum (make-product (deriv (multiplier expr) var)
  56.                             (multiplicand expr))
  57.               (make-product (multiplier expr)
  58.                             (deriv (multiplicand expr) var))))
  59.   (define (power-rule expr var)
  60.     (make-product (exponent expr)
  61.                   (make-product (make-exponentiation (base expr)
  62.                                                      (sub1 (exponent expr)))
  63.                                 (deriv (base expr) var))))
  64.   (put '+ sum-rule)
  65.   (put '* product-rule)
  66.   (put '** power-rule))
  67.  
  68. (install-differentiation-rules)
  69.  
  70. (deriv '(+ (* x y) (** x 3)) 'x)
  71. ;; '(+ y (* 3 (** x 2)))
  72. (deriv '(+ (* x y) (** x 3)) 'y)
  73. ;; 'x
  74.  
  75. ;; d.  If we indexed procedures by type and operator instead of by operator and
  76. ;; type we would only have to change put and get by interchanging the
  77. ;; parameters.  Everything else would work the same.
  78.  
  79. ;;;;;;;;;;
  80. ;; 2.74 ;;
  81. ;;;;;;;;;;
  82.  
  83. ;; We need to create a proc table indexed by operation and type.  The divisions
  84. ;; are the types, and the proc table would yield the correct procedure for that
  85. ;; operation that worked on that division's files.
  86.  
  87. (define (get-record division name)
  88.   ((get 'record division) name))
  89.  
  90. (define (get-salary division name)
  91.   ((get 'salary division) name))
  92.  
  93. (define (find-employee-record name divisions)
  94.   (cond [(null? divisions)
  95.          (error "name not found -- FIND-EMPLOYEE-RECORD" name)]
  96.         [else
  97.           (define record (get-record (first divisions) name))
  98.           (or record
  99.               (find-employee-record name (rest divisions)))]))
  100.  
  101. ;; When acquiring a new division, headquarters will have to add a new column of
  102. ;; procedures to the proc table.
  103.  
  104. ;;;;;;;;;;
  105. ;; 2.75 ;;
  106. ;;;;;;;;;;
  107.  
  108. (define (make-from-mag-ang r a)
  109.   (define (dispatch op)
  110.     (cond [(eq? op 'real-part) (* r (cos a))]
  111.           [(eq? op 'imag-part) (* r (sin a))]
  112.           [(eq? op 'magnitude) r]
  113.           [(eq? op 'angle) a]
  114.           [else (error "unknown op --  MAKE-FROM-MAG-ANG" op)]))
  115.   dispatch)
  116.  
  117. ;;;;;;;;;;
  118. ;; 2.76 ;;
  119. ;;;;;;;;;;
  120.  
  121. ;; We want to write a program that performs different operations on a data object
  122. ;; represented in different ways.  For each operation and each representation,
  123. ;; there will be a different procedure that implements that operation on that
  124. ;; representation.  How do we organize all these procedures to make later
  125. ;; modifying our program as simple as possible?
  126.  
  127. ;; There are three possibilities:
  128.  
  129. ;; We can sort the procedures by operation, and have one definition for each
  130. ;; operation that contains all the procedures implementing that operation on all
  131. ;; the different representations.  This is the direct dispatch method.  The
  132. ;; operations are called generic operations because they operate on data
  133. ;; represented in different ways.  Direct dispatch is a good method if you think
  134. ;; you'll be adding new operations but no new representations because then you
  135. ;; only need to add a new definition for each new operation without modifying the
  136. ;; definitions of the already implemented operations.
  137.  
  138. ;; We could also sort the procedures by representation type, and then define a
  139. ;; dispatch function for each type that takes an operation as a parameter and
  140. ;; returns the correct procedure that implements that operation on that
  141. ;; representation type.  This is the message-passing style.  Message-passing is a
  142. ;; good method if you'll be adding new types but no new operations because then
  143. ;; you only need to add a new dispatch definition for each new representation
  144. ;; without modifying the dispatch functions of the other already implemented
  145. ;; types.
  146.  
  147. ;; The third possibility is to sort the procedures by operation and type, and
  148. ;; store all the procedures in a two-dimensional table.  This is data-driven
  149. ;; programming.  Data-driven programming is a good choice whether you'll be adding
  150. ;; new operations or new types, but it's best if you'll be adding both.
Add Comment
Please, Sign In to add comment