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)) のような、標準の代数記法となる。現在の微分プログラムが相変わらず動作するように、この記法の適切な述語、選択子、構成子が定義出来るか?
答え
適切な述語、選択子、構成子が定義するためには、「演算子は必ず二つの項目をとり、式は必ず括弧で囲われている」状態に式を再構成するフェーズが必要となる。