SICPを読む(70) 問題 2.57-2.58 記号微分(2)

微分を一気に乗り切るぞぉ〜。

問題 2.57

いやぁ、大失敗。

失敗例。

(define (make-sum-iter ex2)
  (fold-right (lambda (ex l)
                (cond ((=number? ex 0) l)
                      ((and (number? ex) (pair? l) (number? (car l)))
                       (cons (+ ex (car l)) (cdr l)))
                      (else (cons ex l))))
              '() ex2))
(define (make-sum ex1 ex2)
  (define l (make-sum-iter (cons ex1 ex2)))
  (cond ((null? l) 0)
        ((null? (cdr l)) (car l))
        (else
          (cons '+ l))))
(make-sum 'x '(1 2 3 4))
; (+ x 10)

fold使えばいいじゃん!うまくいきそうだ!!

と思って、ここまで書いた所でふと気付く。

(deriv (augend exp) var)

augend前に再帰してた!!しまった。残念ながらこれではうまくいかない。

正解は、

(define (augend s)
  (if (null? (cdddr s))
      (caddr s)
      (cons '+ (cddr s))))

これだけカヨ・・・。

問題 2.58

中置に直せばいいだけ。

(define (addend s) (car s))
(define (augend s) (if (null? (cdddr s))
                       (caddr s)
                       (cddr s)))
(define (make-sum ex1 ex2)
  (cond ((=number? ex1 0) ex2)
        ((=number? ex2 0) ex1)
        ((and (number? ex1) (number? ex2)) (+ ex1 ex2))
        (else
          (list ex1 '+ ex2))))

足し算以外もおんなじような感じ。

つまり、後置も可能。

記号微分から学んだこと

文法(前置、中置、後置)を変えても、「中心的なプログラムを変える必要は無い」。データ構造と、実行部分、それらをつなぐ部分をしっかり切り分けてれば、変更は最小限に抑えられる。

つまり、適切な抽象化がされていれば「Scheme中置記法でも作れる」ハズ・・・理論上ね。理論上。