問題2.73 – SICP(計算機プログラムの構造と解釈)その84
2009年01月28日
問題2.73
2.3.2 節の記号微分を行うプログラム。
(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)))) ;; この部分にさらに規則を追加できる (else (error "unknown expression type -- DERIV" exp)))) (deriv '(+ 1 2 3) 'x) gosh> 0 (deriv '(+ x y z) 'x) gosh> 1 (deriv '(+ x 3) 'x) gosh> 1 (deriv '(+ (+ x x x) (+ x x x)) 'x) gosh> 6 (deriv '(* x y) 'x) gosh> y (deriv '(* (* x y) (+ x 3)) 'x) gosh> (+ (* x y) (* y (+ x 3)))
データ主導プログラミングに修正したもの。
(define (deriv exp var) (cond ((number? exp) 0) ((variable? exp) (if (same-variable? exp var) 1 0)) (else ((get 'deriv (operator exp)) (operands exp) var)))) (define (operator exp) (car exp)) (define (operands exp) (cdr exp))
問題 a.
最初のプログラムとの違いは以下の部分のみ。
((get 'deriv (operator exp)) (operands exp) var)
型である演算子記号(+
, *
)と演算である deriv
から、対応する演算を選び実行する。
number?
、variable?
は引数がリストでないために型を持たないから、データ主導の振り分けに組み込めない。
型 | |||
---|---|---|---|
+ |
* |
||
演算 | deriv |
deriv-sum |
deriv-product |
make |
make-sum |
make-product |
問題b.
和の微分
(define (install-sum-package) ;; 内部手続き (define (addend s) (car s)) (define (augend s) (if (null? (cddr s)) (cadr s) (cons '+ (cdr s)))) (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 (deriv-sum exp var) (make-sum (deriv (addend exp) var) (deriv (augend exp) var))) ;; システムの他の部分とのインターフェース (put 'make '+ make-sum) (put 'deriv '+ deriv-sum) 'done) (install-sum-package) gosh> done (deriv '(+ 1 2 3) 'x) gosh> 0 (deriv '(+ x y z) 'x) gosh> 1 (deriv '(+ x 3) 'x) gosh> 1 (deriv '(+ (+ x x x) (+ x x x)) 'x) gosh> 6
積の微分
(define (install-product-package) ;; 内部手続き (define (multiplier p) (car p)) (define (multiplicand p) (if (null? (cddr p)) (cadr p) (cons '* (cdr p)))) (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 (deriv-product exp var) ((get 'make '+) (make-product (multiplier exp) (deriv (multiplicand exp) var)) (make-product (deriv (multiplier exp) var) (multiplicand exp)))) ;; 他の部分とのインターフェース (put 'make '* make-product) (put 'deriv '* deriv-product) 'done) (install-product-package) gosh> done (deriv '(* x y) 'x) gosh> y (deriv '(* (* x y) (+ x 3)) 'x) gosh> (+ (* x y) (* y (+ x 3)))
問題c.
べき乗の微分
(define (install-exponent-package) ;; 内部手続き (define (base s) (car s)) (define (exponent s) (cadr s)) (define (make-exponentiation b e) (cond ((=number? e 0) 1) ((=number? e 1) b) (else (list '** b e)))) (define (deriv-exponentation exp var) (let ((make-p (get 'make '*))) (make-p (make-p (exponent exp) (make-exponentiation (base exp) (- (exponent exp) 1))) (deriv (base exp) var)))) ;; 他の部分とのインターフェース (put 'make '** make-exponentiation) (put 'deriv '** deriv-exponentation) 'done) (install-exponent-package) gosh> done (deriv '(** x 2) 'x) gosh> (* 2 x) (deriv '(** x 1) 'x) gosh> 1 (deriv '(** x 0) 'x) gosh> 0
問題d.
各手続きの put
の引数の"演算"と"型"を逆転すればよい。
計算機プログラムの構造と解釈
posted with amazlet at 08.11.07
ジェラルド・ジェイ サスマン ジュリー サスマン ハロルド エイブルソン
ピアソンエデュケーション
売り上げランキング: 6542
ピアソンエデュケーション
売り上げランキング: 6542