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/ech2support.scmからダウンロードできますね。