1 (define (test-case actual expected)
10 (define (variable? x) (symbol? x))
11 (define (same-variable? v1 v2)
12 (and (variable? v1) (variable? v2) (eq? v1 v2)))
13 (define (make-sum a1 a2) (list '+ a1 a2))
14 (define (make-product m1 m2) (list '* m1 m2))
16 (and (pair? x) (eq? (car x) '+)))
17 (define (addend s) (cadr s))
18 (define (augend s) (caddr s))
20 (and (pair? x) (eq? (car x) '*)))
21 (define (multiplier p) (cadr p))
22 (define (multiplicand p) (caddr p))
24 (define (make-sum a1 a2)
25 (cond ((=number? a1 0) a2)
27 ((and (number? a1) (number? a2)) (+ a1 a2))
28 (else (list '+ a1 a2))))
29 (define (=number? exp num)
30 (and (number? exp) (= exp num)))
32 (define (make-product m1 m2)
33 (cond ((or (=number? m1 0) (=number? m2 0)) 0)
36 ((and (number? m1) (number? m2)) (* m1 m2))
37 (else (list '* m1 m2))))
39 (define (deriv exp var)
40 (cond ((number? exp) 0)
41 ((variable? exp) (if (same-variable? exp var) 1 0))
42 ((sum? exp) (make-sum (deriv (addend exp) var)
43 (deriv (augend exp) var)))
44 ((product? exp) (make-sum
45 (make-product (multiplier exp)
46 (deriv (multiplicand exp) var))
47 (make-product (deriv (multiplier exp) var)
49 ((and (exponentiation? exp)
50 (number? (exponent exp)))
52 (make-product (exponent exp)
53 (make-exponentiation (base exp)
54 (make-sum (exponent exp) -1)))
55 ;; or (- (exponent exp) 1)
56 (deriv (base exp) var)))
57 (error "unknown expression type -- DERIV" exp)))
59 (define (exponentiation? exp)
60 (and (pair? exp) (eq? (car exp) '**)))
63 (define (exponent exp)
66 (define (make-exponentiation base exponent)
67 (cond ((and (=number? base 0) (=number? exponent 0)) (error "0^0 undefined"))
68 ((=number? exponent 0) 1)
71 ((and (number? base) (number? exponent)) (expt base exponent))
72 ((=number? exponent 1) base)
73 (else (list '** base exponent))))
74 ;; warning, does not warn if x = 0 for 0^x
76 ;; (test-case (make-exponentiation 0 0) "0^0 undefined")
77 ;; (test-case (make-exponentiation 0 1) 0)
78 ;; (test-case (make-exponentiation 1 0) 1)
79 ;; (test-case (make-exponentiation 5 5) 3125)
80 ;; (test-case (make-exponentiation 'x 0) 1) ;; bug -- what if x = 0?
81 ;; (test-case (make-exponentiation 'x 1) 'x)
82 ;; (test-case (make-exponentiation 1 'x) 1)
83 ;; (test-case (make-exponentiation 'x 5) '(** x 5))
84 ;; (test-case (make-exponentiation 0 'x) 0) ;; bug -- what if x = 0?
85 ;; (test-case (make-exponentiation 5 'x) '(** 5 x))
86 ;; (test-case (make-exponentiation 'x 'x) '(** x x))
88 (test-case (deriv (make-sum (make-sum (make-exponentiation 'x 3)
89 (make-product 3 (make-exponentiation 'x 2)))
96 ;; Exercise 2.57. Extend the differentiation program to handle sums and products of arbitrary numbers of (two or more) terms. Then the last example above could be expressed as
98 ;; (deriv '(* x y (+ x 3)) 'x)
100 ;; Try to do this by changing only the representation for sums and products, without changing the deriv procedure at all. For example, the addend of a sum would be the first term, and the augend would be the sum of the rest of the terms.
102 (define (make-sum . exps)
103 (let* ((nums (filter number? exps))
104 (non-nums (filter (lambda (exp) (not (number? exp))) exps))
105 (num (fold-right + 0 nums)))
106 (cond ((= num 0) (cond ((null? non-nums) 0)
107 ((null? (cdr non-nums)) (car non-nums))
108 (else (append (list '+) non-nums))))
109 ((null? non-nums) num)
110 (else (append (list '+)
113 (define (make-sum . exps)
114 (let* ((nums (filter number? exps))
115 (non-nums (filter (lambda (exp) (not (number? exp))) exps))
116 (num (fold-right + 0 nums)))
117 (cond ((= num 0) (cond ((null? non-nums) 0)
118 ((null? (cdr non-nums)) (car non-nums))
119 (else (append (list '+) non-nums))))
120 ((null? non-nums) num)
121 (else (append (list '+)
124 (define (make-product . exps)
125 (let* ((nums (filter number? exps))
126 (non-nums (filter (lambda (exp) (not (number? exp))) exps))
127 (num (fold-right * 1 nums)))
128 (cond ((null? exps) 1)
130 ((null? non-nums) num)
131 ((null? (cdr non-nums)) (if (= num 1)
133 (append (list '* num) non-nums)))
136 (append (list '* num) non-nums))))))
138 ;; ((= nums 1) (cond ((null? non-nums) 1)
139 ;; ((null? (cdr non-nums)) (car non-nums))
140 ;; (else (append (list '*) non-nums))))
143 (test-case (make-sum) 0)
144 (test-case (make-sum 0) 0)
145 (test-case (make-sum 0 'x) 'x)
146 (test-case (make-sum 1 2 3 4 5) 15)
147 (test-case (make-sum 1 'x) '(+ x 1))
148 (test-case (make-sum 1 5 'x) '(+ x 6))
149 (test-case (make-sum 1 5 'x 'y) '(+ x y 6))
150 (test-case (make-sum -3 3 'x 'y) '(+ x y))
151 (test-case (make-sum -3 3 'x) 'x)
152 (test-case (make-sum 'a 'b 'c 'd 1 2 3 -6 -7 5) '(+ a b c d -2))
153 (test-case (make-sum 'a 'b 'c 'd 1 2 3 -6 -7 4 3) '(+ a b c d))
154 (test-case (make-sum (make-product 5 'x)
157 '(+ (* 5 x) (* 3 y) 3))
158 (test-case (make-sum (make-product 5 'x)
159 (make-product 2 0 'y)
160 (make-product (make-sum 5 -5) 'x)
161 (make-product (make-sum 2 4 -6) 'y)
162 (make-product (make-product 0 1) 'z)
166 '(+ (* 5 x) (* 4 z)))
168 (test-case (make-product) 1)
169 (test-case (make-product 1) 1)
170 (test-case (make-product 5) 5)
171 (test-case (make-product 'x) 'x)
172 (test-case (make-product 5 'x) '(* 5 x))
173 (test-case (make-product 5 2) 10)
174 (test-case (make-product 0) 0)
175 (test-case (make-product 0 1 3 2) 0)
176 (test-case (make-product 0 'x) 0)
177 (test-case (make-product 5 2 'x) '(* 10 x))
178 (test-case (make-product 5 'x 'y 'z 0) 0)
179 (test-case (make-product 5 'x 'y 'z) '(* 5 x y z))
180 (test-case (make-product 5 'x 2 -3 'y) '(* -30 x y))
181 (test-case (make-product 5 1/5 'x) 'x)
182 (test-case (make-product 5 1/5 'x 'y) '(* x y))
183 (test-case (make-product (make-sum 5 6 4 -2)
187 (test-case (make-product (make-sum (make-sum 2 4)
193 (define (addend s) (cadr s))
194 (define (augend s) (apply make-sum (cddr s)))
196 ;; (if (null? (cdddr s))
198 ;; (apply make-sum (cddr s))))
200 (define (multiplier p) (cadr p))
201 (define (multiplicand p) (apply make-product (cddr p)))
203 (test-case (augend (make-sum 1 'x)) 1)
204 (test-case (augend (make-sum 1 5 'x)) 6)
205 (test-case (augend (make-sum 1 5 'x 'y)) '(+ y 6))
206 (test-case (augend (make-sum -3 3 'x 'y)) 'y)
207 (test-case (augend (make-sum 'a 'b 'c 'd 1 2 3 -6 -7 5)) '(+ b c d -2))
208 (test-case (augend (make-sum 'a 'b 'c 'd 1 2 3 -6 -7 4 3)) '(+ b c d))
209 (test-case (augend (make-sum (make-product 5 'x)
213 (test-case (augend (make-sum (make-product 5 'x)
214 (make-product 2 0 'y)
215 (make-product (make-sum 5 -5) 'x)
216 (make-product (make-sum 2 4 -6) 'y)
217 (make-product (make-product 0 1) 'z)
223 (test-case (multiplicand (make-product 5 'x)) 'x)
224 (test-case (multiplicand (make-product 5 'x 'y 'z)) '(* x y z))
225 (test-case (multiplicand (make-product 5 'x 2 -3 'y)) '(* x y))
226 (test-case (multiplicand (make-product (make-sum 5 6 4 -2)
230 (test-case (deriv '(* x y (+ x 3)) 'x) '(+ (* x y) (* y (+ x 3))))
231 ;; (make-sum (make-product 'x (deriv '(* y (+ x 3)) 'x))
233 ;; (make-sum (make-product 'x 'y)
235 ;; (make-sum '(* x y)
237 ;; '(+ (* x y) (* y (+ x 3)))