#lang racket
;;;;;;;;;;
;; 2.73 ;;
;;;;;;;;;;
(define deriv-table (make-hash))
(define (put type item) (hash-set! deriv-table type item))
(define (get type) (hash-ref deriv-table type))
(define (=number? x y) (and (number? x) (number? y) (= x y)))
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (operator expr) (first expr))
(define (operands expr) (rest expr))
(define (deriv expr var)
(cond [(number? expr) 0]
[(variable? expr) (if (same-variable? expr var) 1 0)]
[else ((get (operator expr)) (operands expr) var)]))
;; a. number? and same-variable? cannot be put in the op table because they do
;; not operate on tagged expressions.
;; constructors and selectors
(define (make-sum a1 a2)
(cond [(=number? a1 0) a2]
[(=number? a2 0) a1]
[(and (number? a1) (number? a2)) (+ a1 a2)]
[else (list '+ a1 a2)]))
(define (addend s) (first s))
(define (augend s) (second s))
(define (make-product m1 m2)
(cond [(or (=number? m1 0) (=number? m2 0)) 0]
[(=number? m1 1) m2]
[(=number? m2 1) m1]
[(and (number? m1) (number? m2)) (* m1 m2)]
[else (list '* m1 m2)]))
(define (multiplier p) (first p))
(define (multiplicand p) (second p))
(define (make-exponentiation base expo)
(cond [(=number? expo 0) 1]
[(=number? expo 1) base]
[(and (number? base) (number? expo)) (expt base expo)]
[else (list '** base expo)]))
(define (base e) (first e))
(define (exponent e) (second e))
(define (install-differentiation-rules)
(define (sum-rule expr var)
(make-sum (deriv (addend expr) var)
(deriv (augend expr) var)))
(define (product-rule expr var)
(make-sum (make-product (deriv (multiplier expr) var)
(multiplicand expr))
(make-product (multiplier expr)
(deriv (multiplicand expr) var))))
(define (power-rule expr var)
(make-product (exponent expr)
(make-product (make-exponentiation (base expr)
(sub1 (exponent expr)))
(deriv (base expr) var))))
(put '+ sum-rule)
(put '* product-rule)
(put '** power-rule))
(install-differentiation-rules)
(deriv '(+ (* x y) (** x 3)) 'x)
;; '(+ y (* 3 (** x 2)))
(deriv '(+ (* x y) (** x 3)) 'y)
;; 'x
;; d. If we indexed procedures by type and operator instead of by operator and
;; type we would only have to change put and get by interchanging the
;; parameters. Everything else would work the same.
;;;;;;;;;;
;; 2.74 ;;
;;;;;;;;;;
;; We need to create a proc table indexed by operation and type. The divisions
;; are the types, and the proc table would yield the correct procedure for that
;; operation that worked on that division's files.
(define (get-record division name)
((get 'record division) name))
(define (get-salary division name)
((get 'salary division) name))
(define (find-employee-record name divisions)
(cond [(null? divisions)
(error "name not found -- FIND-EMPLOYEE-RECORD" name)]
[else
(define record (get-record (first divisions) name))
(or record
(find-employee-record name (rest divisions)))]))
;; When acquiring a new division, headquarters will have to add a new column of
;; procedures to the proc table.
;;;;;;;;;;
;; 2.75 ;;
;;;;;;;;;;
(define (make-from-mag-ang r a)
(define (dispatch op)
(cond [(eq? op 'real-part) (* r (cos a))]
[(eq? op 'imag-part) (* r (sin a))]
[(eq? op 'magnitude) r]
[(eq? op 'angle) a]
[else (error "unknown op -- MAKE-FROM-MAG-ANG" op)]))
dispatch)
;;;;;;;;;;
;; 2.76 ;;
;;;;;;;;;;
;; We want to write a program that performs different operations on a data object
;; represented in different ways. For each operation and each representation,
;; there will be a different procedure that implements that operation on that
;; representation. How do we organize all these procedures to make later
;; modifying our program as simple as possible?
;; There are three possibilities:
;; We can sort the procedures by operation, and have one definition for each
;; operation that contains all the procedures implementing that operation on all
;; the different representations. This is the direct dispatch method. The
;; operations are called generic operations because they operate on data
;; represented in different ways. Direct dispatch is a good method if you think
;; you'll be adding new operations but no new representations because then you
;; only need to add a new definition for each new operation without modifying the
;; definitions of the already implemented operations.
;; We could also sort the procedures by representation type, and then define a
;; dispatch function for each type that takes an operation as a parameter and
;; returns the correct procedure that implements that operation on that
;; representation type. This is the message-passing style. Message-passing is a
;; good method if you'll be adding new types but no new operations because then
;; you only need to add a new dispatch definition for each new representation
;; without modifying the dispatch functions of the other already implemented
;; types.
;; The third possibility is to sort the procedures by operation and type, and
;; store all the procedures in a two-dimensional table. This is data-driven
;; programming. Data-driven programming is a good choice whether you'll be adding
;; new operations or new types, but it's best if you'll be adding both.
Comments
0 B
|👍
/👎