SICP問題2.73
a. データ主導への書き換えは何をやっているのか?述語numer?やvariable?がデータ主導の振り分けに吸収できない理由は?
二項間の演算に関わる微分の簡約規則を演算、その代数演算の種類を型としてデータ主導プログラミングで書き直している。
number? や variable? が振り分けできないのは、これらがリストで実現されている型ではなくschemeの型を使っていため。
b. 和と積の微分手続きを書き、上のプログラムで使う表に、それらを設定するのに必用な補助プログラムを書け
; attach-tag は流用 ; (define (attach-tag type-tag contents) ; (cons type-tag contents)) ; apply-genericも ; 加算/乗算の手続き自体は2.3.2節から流用する ; 加算ならばmake-sum, 乗算ならばmake-product を実行するmakeを定義する (define (install-sum-package) (define (addend operands) (car operands)) ; 加数 (define (augend operands) ; 被加数 (if (null? (cddr operands)) (cadr operands) (cons '+ (cdr operands)))) (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) ) (define (install-product-package) (define (multiplier operands) (car operands)) ; 乗数 (define (multiplicand operands) ; 被乗数 (if (null? (cddr operands)) (cadr operands) (cons '* (cdr operands)))) (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) )
c. (問題2.56)のべき乗のような、その他の微分規則を選び、このデータ主導システムに設定せよ。
(define (install-exponentiation-package) (define (base operands) (car operands)) (define (exponent operands) (cadr operands)) (define (make-exponentiation b e) (cond ((=number? e 0) 1) ((=number? e 1) b) ((and (number? b) (number? e)) (expt b e)) (else (list '** b e)))) (define (deriv-exponentiation exp var) ((get 'make '*) ((get 'make '*) (exponent exp) (make-exponentiation (base exp) ((get 'make '+) (exponent exp) -1))) (deriv (base exp) var))) (put 'make '** make-exponentiation) (put 'deriv '** deriv-exponentiation) )
d. この代数式操作では、式の型はそれを結合している代数演算であるが、手続きの目印を反対にし、derivの振り分けを
((get (operator exp) 'deriv) (operands exp) var)
のようにした場合、微分システムには対応したどのような変更が必要か。
以下の例のように各 put の引数を逆にすれば良い。
(put 'deriv '+ deriv-sum)
; => (put '+ 'deriv deriv-sum)
(put 'deriv '* deriv-product)
; => (put '* 'deriv deriv-product)
なお、put, getの定義についてはComplete Code from SICP 2/eのch2support.scmからダウンロードできますね。