patternMinor
Extend sums and products functions
Viewed 0 times
extendsumsandfunctionsproducts
Problem
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
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.
I wrote the following solution.
```
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var) 1 0))
((sum? exp)
(make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
((exponentiation? exp)
(make-product (exponent exp)
(make-exponentiation (base exp) (- (exponent exp) 1))))
(else
(error "unknown expression type -- DERIV" exp))))
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (make-sum . a)
(define (iter sum rest)
(cond ((null? rest) (if (zero? sum) '() (list sum)))
((=number? (car rest) 0) (iter sum (cdr rest)))
((number? (car rest)) (iter (+ sum (car rest)) (cdr rest)))
(else (cons (car rest) (iter sum (cdr rest))))))
(let ((result (iter 0 a)))
(if (= (length result) 1)
(car result)
(cons '+ result))))
(define (=number? exp num)
(and (number? exp) (= exp num)))
(define (make-product . a)
(define (iter product rest)
(cond ((null? rest) (if (= 1 product) '() (list product)))
((=number? (car rest) 1) (iter product
(cdr
differentiation program to handle sums
and products of arbitrary numbers of
(two or more) terms. Then the last
example above could be expressed as
(deriv '(* x y (+ x 3)) 'x)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.
I wrote the following solution.
```
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var) 1 0))
((sum? exp)
(make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
((exponentiation? exp)
(make-product (exponent exp)
(make-exponentiation (base exp) (- (exponent exp) 1))))
(else
(error "unknown expression type -- DERIV" exp))))
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (make-sum . a)
(define (iter sum rest)
(cond ((null? rest) (if (zero? sum) '() (list sum)))
((=number? (car rest) 0) (iter sum (cdr rest)))
((number? (car rest)) (iter (+ sum (car rest)) (cdr rest)))
(else (cons (car rest) (iter sum (cdr rest))))))
(let ((result (iter 0 a)))
(if (= (length result) 1)
(car result)
(cons '+ result))))
(define (=number? exp num)
(and (number? exp) (= exp num)))
(define (make-product . a)
(define (iter product rest)
(cond ((null? rest) (if (= 1 product) '() (list product)))
((=number? (car rest) 1) (iter product
(cdr
Solution
Your have the right ideas for implementing
Within the two functions, you employ an inner function
One may allow
Finally, there are several cases that must be handled when iteration terminates:
Here's an implementation (naming scheme is slightly different from yours--in the
One may also simplify the definitions of
Note the similarities between
make-sum and make-product. You may improve upon them in the following ways, in my opinion.Within the two functions, you employ an inner function
iter to partition numeric and non-numeric terms. Traditionally, one uses the name iter to represent an iterative function; your definition, however, is most certainly recursive. To make it truly iterative, one may use two accumulators--one for the sum of all numeric terms and the other for the rest of the terms. Then one may return the cons of the two accumulators when the iteration terminates.One may allow
make-sum (and similarly make-product) to handle other sum-type objects in its terms list as well--simply test with sum?, then append its terms.Finally, there are several cases that must be handled when iteration terminates:
rest may be empty or it may contain one or more items; sum-numbers may be zero or non-zero.Here's an implementation (naming scheme is slightly different from yours--in the
iter function, terms is the list of remaining terms to be iterated upon, sum-numbers is the sum of all numeric terms seen so far, rest is a list of all non-numeric terms seen so far):(define (make-sum . terms)
(define (iter terms sum-numbers rest)
(cond
((null? terms) (cons sum-numbers rest))
((=number? (car terms) 0) (iter (cdr terms) sum-numbers rest))
((number? (car terms)) (iter (cdr terms) (+ sum-numbers (car terms)) rest))
((sum? (car terms)) (iter (append (cdar terms) (cdr terms)) sum-numbers rest))
(else (iter (cdr terms) sum-numbers (cons (car terms) rest)))))
(let*
((result (iter terms 0 null))
(sum-numbers (car result))
(rest (cdr result)))
(if (null? rest)
sum-numbers
(if (zero? sum-numbers)
(if (null? (cdr rest))
(car rest)
(cons '+ rest))
(cons '+ (cons sum-numbers rest))))))
(define (make-product . terms)
(define (iter terms sum-numbers rest)
(cond
((null? terms) (cons sum-numbers rest))
((=number? (car terms) 0) (cons 0 null))
((=number? (car terms) 1) (iter (cdr terms) sum-numbers rest))
((number? (car terms)) (iter (cdr terms) (* sum-numbers (car terms)) rest))
((product? (car terms)) (iter (append (cdar terms) (cdr terms)) sum-numbers rest))
(else (iter (cdr terms) sum-numbers (cons (car terms) rest)))))
(let*
((result (iter terms 1 null))
(sum-numbers (car result))
(rest (cdr result)))
(if (null? rest)
sum-numbers
(if (zero? sum-numbers)
(if (null? (cdr rest))
(car rest)
(cons '* rest))
(cons '* (cons sum-numbers rest))))))One may also simplify the definitions of
augend and multiplicand by using make-sum and make-product respectively:(define (augend s) (apply make-sum (cddr s)))
(define (multiplicand p) (apply make-product (cddr p)))Note the similarities between
make-sum and make-product. It may be possible to factor out some code. One may also use library functions such as partition (if available) to simplify the code.Code Snippets
(define (make-sum . terms)
(define (iter terms sum-numbers rest)
(cond
((null? terms) (cons sum-numbers rest))
((=number? (car terms) 0) (iter (cdr terms) sum-numbers rest))
((number? (car terms)) (iter (cdr terms) (+ sum-numbers (car terms)) rest))
((sum? (car terms)) (iter (append (cdar terms) (cdr terms)) sum-numbers rest))
(else (iter (cdr terms) sum-numbers (cons (car terms) rest)))))
(let*
((result (iter terms 0 null))
(sum-numbers (car result))
(rest (cdr result)))
(if (null? rest)
sum-numbers
(if (zero? sum-numbers)
(if (null? (cdr rest))
(car rest)
(cons '+ rest))
(cons '+ (cons sum-numbers rest))))))
(define (make-product . terms)
(define (iter terms sum-numbers rest)
(cond
((null? terms) (cons sum-numbers rest))
((=number? (car terms) 0) (cons 0 null))
((=number? (car terms) 1) (iter (cdr terms) sum-numbers rest))
((number? (car terms)) (iter (cdr terms) (* sum-numbers (car terms)) rest))
((product? (car terms)) (iter (append (cdar terms) (cdr terms)) sum-numbers rest))
(else (iter (cdr terms) sum-numbers (cons (car terms) rest)))))
(let*
((result (iter terms 1 null))
(sum-numbers (car result))
(rest (cdr result)))
(if (null? rest)
sum-numbers
(if (zero? sum-numbers)
(if (null? (cdr rest))
(car rest)
(cons '* rest))
(cons '* (cons sum-numbers rest))))))(define (augend s) (apply make-sum (cddr s)))
(define (multiplicand p) (apply make-product (cddr p)))Context
StackExchange Code Review Q#1998, answer score: 5
Revisions (0)
No revisions yet.