SICP 読み (81) 2.5.3 例: 記号代数

_大仕事_に着手してみる。

問題 2.90

とりあえず、依存する手続きを以下にまとめて。

2.90/lib/2.5.1.scm

(define (assoc key records)
  (cond ((null? records) #f)
	((equal? key (caar records)) (car records))
	(else (assoc key (cdr records)))))

(define (make-table)
  (let ((local-table (list '*table*)))
    (define (lookup key-1 key-2)
      (let ((subtable (assoc key-1 (cdr local-table))))
	(if subtable
	    (let ((record (assoc key-2 (cdr subtable))))
	      (if record
		  (cdr record)
		  #f))
	    #f)))
    (define (insert! key-1 key-2 value)
      (let ((subtable (assoc key-1 (cdr local-table))))
	(if subtable
	    (let ((record (assoc key-2 (cdr subtable))))
	      (if record
		  (set-cdr! record value)
		  (set-cdr! subtable
			    (cons (cons key-2 value) (cdr subtable)))))
	    (set-cdr! local-table
		      (cons (list key-1
				  (cons key-2 value))
			    (cdr local-table)))))
      'ok)
    (define (dispatch m)
      (cond ((eq? m 'lookup-proc) lookup)
	    ((eq? m 'insert-proc!) insert!)
	    (else (error "Unknown operation -- TABLE" m))))
    dispatch))

(define operation-table (make-table))
(define get (operation-table 'lookup-proc))
(define put (operation-table 'insert-proc!))

(define (attach-tag type-tag contents)
  (cons type-tag contents))
(define (type-tag datum)
  (cond ((number? datum) 'scheme-number)
	((pair? datum) (car datum))
	(else
	 (error "Bad tagged datum -- TYPE TAG" datum))))
(define (contents datum)
  (cond ((number? datum) datum)
	((pair? datum) (cdr datum))
	(else
	 (error "Bad tagged datum -- CONTENTS" datum))))

(define (apply-generic op . args)
  (let ((type-tags (map type-tag args)))
    (let ((proc (get op type-tags)))
      (if proc
	  (apply proc (map contents args))
	  (error
	   "No method for these types -- APPLY-GENERIC"
	   (list op type-tags))))))

(define (add x y) (apply-generic 'add x y))
(define (sub x y) (apply-generic 'sub x y))
(define (mul x y) (apply-generic 'mul x y))
(define (div x y) (apply-generic 'div x y))
(define (=zero? x) (apply-generic '=zero? x))

(define (install-scheme-number-package)
  (put 'add '(scheme-number scheme-number) +)

  (put 'sub '(scheme-number scheme-number) -)

  (put 'mul '(scheme-number scheme-number) *)

  (put 'div '(scheme-number scheme-number) /)

  (put '=zero? '(scheme-number) zero?)

  (put 'make 'scheme-number
       (lambda (x) x))
  'done)

(define (make-scheme-number n)
  ((get 'make 'scheme-number) n))

試験もイチから書く。ちなみに上記の手続きな試験は略。基本的に_項リスト_関連の手続きをパケジにしてしまえ、という事だと思っているので、それより上位に位置する手続き達は纏める事ができるハズ。
がしかし、項リストの取扱いはちょっと検討が必要だな。
p.113 の図 2.24 な手法で良いのかどうか。

  • 引数が term-list 一発の手続きは楽そげ
    • first-term
    • rest-terms
    • empty-termlist?
  • the-empty-termlist も tag 付けて '() 返却で良いのか?
  • term なソレが微妙 (つってもタダのリスト)
    • make-term
    • order
    • coeff
  • 一番微妙なのが adjoin-term でどうしたものか
    • apply-generic で処理するのであれば term にも tag 打つ必要あり?
    • 違う。apply-generic で手続きを返して term を渡すんか?
(define (adjoin-term term-list)
  (lambda (term)
    (if (=zero? (coeff term))
	term-list
	(cons term term-list))))

とか

(define (adjoin-term term-list)
  (lambda (term)
    (let f ((term-list term-list))
      (if (> (order term) (length term-list))
	  (f (cons 0 term-list))
	  (cons (coeff term) term-list)))))

みたいな?

う。make-polynomial も修正必要だな。ふたつに分けるんかな? make-sparse-polynomial とか make-dense-polynomial とか。