SICP問題2.91

一元多項式はもうひとつのもので割り,多項式の商と多項式の剰余が得られる
(例)
(x^5 - 1)/(x^2 - 1)=x^3 + x , x - 1
計算方法は
被除数の最高次の項 / 除数の最高次の項 … 商の第一項
被除数 - (商の第一項 * 除数) … 残りの項は再帰的にこの差を除数で割って作る
除数の次数が被除数の次数を超えたら停止して、その被除数を剰余とする
被除数が零になったら、商と剰余に零を返す
となるので、教科書のdiv-termsの定義のかけている式を補って完成させる

(define (div-terms L1 L2)
  (if (empty-termlist? L1)
      (list (the-empty-termlist) (the-empty-termlist))
      (let ((t1 (first-term L1))
            (t2 (first-term L2)))
        (if (> (order t2) (order t1))
            (list (the-empty-termlist) L1)
            (let ((new-c (div (coeff t1) (coeff t2)))
                  (new-o (- (order t1) (order t2))))
              (let ((rest-of-result
                     ; <結果の残りを再帰的に計算する>
                     (div-terms 
                      (sub-terms L1 (mul-terms (list (make-term new-o new-c)) L2))
                      L2)
                     ))
                ; <完全な結果を形成する>
                (list (add-terms (list (make-term new-o new-c))
                                 (car rest-of-result))
                      (cadr rest-of-result))
                ))))))

これを使ったdiv-poly

(define (div-poly p1 p2)
  (if (same-variable? (variable p1) (variable p2))
      (make-poly (variable p1)
                 (div (term-list p1)
                      (term-list p2)))
      (error "Polys not in same var -- DIV-POLY"
             (list p1 p2))))

上記を組み込んだ各パッケージに組み込む。
ただしdense-term-packageの方はいろいろ修正しないと組み込めないので今回はパス。
sparse-term-package

(define (install-sparse-term-package)
  (define (the-empty-termlist) '())
  (define (first-term term-list) (car term-list))
  (define (rest-terms term-list) (cdr term-list))
  (define (empty-termlist? term-list) (null? term-list))
  (define (make-term order coeff) (list order coeff))
  (define (order term) (car term))
  (define (coeff term) (cadr term))
  ; 多項式の和のリストを構成する手続き
  (define (add-terms L1 L2)
    (cond ((empty-termlist? L1) L2)
          ((empty-termlist? L2) L1)
          (else
           (let ((t1 (first-term L1))
                 (t2 (first-term L2)))
             (cond ((> (order t1) (order t2))
                    (adjoin-term 
                     t1 (add-terms (rest-terms L1) L2)))
                   ((< (order t1) (order t2))
                    (adjoin-term
                     t2 (add-terms L1 (rest-terms L2))))
                   (else
                    (adjoin-term
                     (make-term (order t1)
                                (add (coeff t1) (coeff t2)))
                     (add-terms (rest-terms L1) (rest-terms L2)))))))))
  
  ; 二つの多項式の乗の項リスト
  (define (mul-terms L1 L2)
    (if (empty-termlist? L1)
        (the-empty-termlist)
        (add-terms (mul-term-by-all-terms (first-term L1) L2)
                   (mul-terms (rest-terms L1) L2))))
  (define (mul-term-by-all-terms t1 L)
    (if (empty-termlist? L)
        (the-empty-termlist)
        (let ((t2 (first-term L)))
          (adjoin-term
            (make-term (add (order t1) (order t2))
                       (mul (coeff t1) (coeff t2)))
            (mul-term-by-all-terms t1 (rest-terms L))))))
  (define (adjoin-term term termlist)
    (if (=zero? (coeff term))
        termlist
        (cons term termlist)))
  (define (negate-termlist L)
    (if (empty-termlist? L)
        L
        (let ((f (first-term L))
              (r (rest-terms L)))
          (adjoin-term
           (make-term (order f)
                      (negate (coeff f)))
           (negate-termlist r)))))
  (define (=zero-term? x)
    (or (empty-termlist? x)
        (if (=zero? (coeff (first-term x)))
            (=zero-term? (rest-terms x))
            #f)))
  (define (sub-terms L1 L2)
    (add-terms L1 (negate-termlist L2)))
  (define (div-terms L1 L2)
    (if (empty-termlist? L1)
        (list (the-empty-termlist) (the-empty-termlist))
        (let ((t1 (first-term L1))
              (t2 (first-term L2)))
          (if (> (order t2) (order t1))
              (list (the-empty-termlist) L1)
              (let ((new-c (div (coeff t1) (coeff t2)))
                    (new-o (- (order t1) (order t2))))
                (let ((rest-of-result
                       ; <結果の残りを再帰的に計算する>
                       (div-terms 
                        (sub-terms L1 (mul-terms (list (make-term new-o new-c)) L2))
                        L2)
                       ))
                  ; <完全な結果を形成する>
                  (list (add-terms (list (make-term new-o new-c))
                                   (car rest-of-result))
                        (cadr rest-of-result))
                  ))))))
  ;; システムの他の部分とのインタフェース
  (define (tag p) (attach-tag 'sparse-term p))
  (put 'add '(sparse-term sparse-term)
       (lambda (p1 p2) (tag (add-terms p1 p2))))
  (put 'mul '(sparse-term sparse-term)
       (lambda (p1 p2) (tag (mul-terms p1 p2))))
  (put 'div '(sparse-term sparse-term)
       (lambda (p1 p2) (tag (div-terms p1 p2))))
  (put '=zero? '(sparse-term)
       (lambda (x) (=zero-term? x)))
  (put 'negate '(sparse-term)
       (lambda (x) (tag (negate-termlist x))))
  (put 'sub '(sparse-term sparse-term)
       (lambda (p1 p2) (tag (sub-terms p1 p2))))
  (put 'make-from-sparse-term 'sparse-term
       (lambda (x) (tag x)))
  (put 'make-from-dense-term 'sparse-term
       (lambda (x) (tag (dense-term->sparse-term x))))
  'done)
(install-sparse-term-package)

(define (make-sparse-term terms)
  ((get 'make-from-sparse-term 'sparse-term) terms))

polynomial-package

(define (install-polynomial-package)
  (define (make-poly variable term-list)
    (cons variable term-list))
  (define (variable p) (car p))
  (define (term-list p) (cdr p))
  (define (variable? x) (symbol? x))
  (define (same-variable? v1 v2)
    (and (variable? v1) (variable? v2) (eq? v1 v2)))
  (define (add-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (add (term-list p1)
                        (term-list p2)))
        (error "Polys not in same var -- ADD-POLY"
               (list p1 p2))))
  (define (mul-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (mul (term-list p1)
                        (term-list p2)))
        (error "Polys not in same var -- MUL-POLY"
               (list p1 p2))))
  (define (=zero-poly? x)
    (=zero? (term-list x)))
  (define (negate-poly x)
    (make-poly (variable x)
               (negate (term-list x))))
  (define (sub-poly x y)
    (add-poly x (negate-poly y)))
  (define (div-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (div (term-list p1)
                        (term-list p2)))
        (error "Polys not in same var -- DIV-POLY"
               (list p1 p2))))
  ;; システムの他の部分とのインタフェース
  (define (tag p) (attach-tag 'polynomial p))
  (put 'add '(polynomial polynomial)
       (lambda (p1 p2) (tag (add-poly p1 p2))))
  (put 'mul '(polynomial polynomial)
       (lambda (p1 p2) (tag (mul-poly p1 p2))))
  (put 'div '(polynomial polynomial)
       (lambda (p1 p2) (tag (div-poly p1 p2))))
  (put 'make 'polynomial
       (lambda (var terms) (tag (make-poly var terms))))
  (put '=zero? '(polynomial)
       (lambda (x) (=zero-poly? x)))
  (put 'negate '(polynomial)
       (lambda (x) (tag (negate-poly x))))
  (put 'sub '(polynomial polynomial)
       (lambda (p1 p2) (tag (sub-poly p1 p2))))
  'done)
(install-polynomial-package)
(define (make-polynomial var terms)
  ((get 'make 'polynomial) var terms))

テスト

(div
 (make-polynomial 'x (make-sparse-term '((5 1) (0 -1))))
 (make-polynomial 'x (make-sparse-term '((2 1) (0 -1)))))
; (polynomial x sparse-term ((3 1) (1 1)) ((1 1) (0 -1)))

OK