SICP問題2.58

a. 前置演算子でなく (x + (3 * (x + (y + 2)))) のような中置き表現の代数式を微分するプログラム(+ や * は常に二つの項をとり、式は完全に括弧で囲まれていると仮定)

(define (sum? x)
  (and (pair? x) (eq? (cadr x) '+)))
(define (addend s) (car s))
(define (augend s) (caddr s))
(define (product? x)
  (and (pair? x) (eq? (cadr x) '*)))
(define (multiplier p) (car p))
(define (multiplicand p) (caddr p))
(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 (=number? exp num)
  (and (number? exp) (= exp num)))
(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 (exponentiation? x)
  (and (pair? x) (eq? (cadr x) '**)))
(define (base x) (cad x))
(define (exponent x) (caddr x))
(define (make-exponentiation b e) 
  (cond ((=number? e 0) 1)
	((=number? e 1) b)
        ; Web で他の人の答え見るとここはいらないっぽい
	((and (number? b) (number? e)) (expt b e))
	(else (list b '** e))))

; deriv (変更なし)
(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 (make-product (exponent exp)
				     (make-exponentiation
				      (base exp) 
				      (make-sum (exponent exp) -1)))
			(deriv (base exp) var)))
	(else
	 (error "unknown expression type -- DERIV" exp))))

b. 不要な括弧は省き、乗算は加算より前に行うと仮定した場合、(x + 3 * (x + y + 2)) のような、標準の代数記法となる。現在の微分プログラムが相変わらず動作するように、この記法の適切な述語、選択子、構成子が定義出来るか?
答え
適切な述語、選択子、構成子が定義するためには、「演算子は必ず二つの項目をとり、式は必ず括弧で囲われている」状態に式を再構成するフェーズが必要となる。