問題解答以前にコードの動作確認ができなくてハマっている問題 2.77。今日こそは片をつけたいものです。
やっぱり、こうなったときにデバッガが無いのは辛いですね、、、
問題解答
問 2.77
さんざん悩んだ挙句、解決。
(define op-table (make-hash-table 'equal?)) (define (put op type item) (if (not (hash-table-exists? op-table op)) (hash-table-put! op-table op (make-hash-table 'equal?))) (let ((type-table (hash-table-get op-table op))) (hash-table-put! type-table type item))) (define (get op type) (if (not (hash-table-exists? op-table op)) (hash-table-put! op-table op (make-hash-table 'equal?))) (let ((type-table (hash-table-get op-table op))) (hash-table-get type-table type)))
値の比較に、デフォルトの eq? を使っていたのがダメだったようです。
gosh> (equal? '(complex) '(complex)) #t gosh> (eq? '(complex) '(complex)) #f
これはわからないです、、、ぐぬぬぬ。
その他にも typo でハマったりしたものの、やっと動作確認ができました。長かった、、、、、
そしてやっと本題。
(magnitude z) の評価される順番。
(define (magnitude z) (apply-generic 'magnitude z))
で apply-generic が呼ばれる。
(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))))))
z は (complex rectangular 3.4) なので、type-tags は (complex)。
proc は complex package で定義した
(put 'magnitude '(complex) magnitude)
で、最初に呼び出されたのと同じ magnitude が抽出される。
二度目の magnutude への引数(apply-generic への引数も同じ)は (map contents args) でタグを一つ剥がされたものなので (rectangular 3 . 4)。
apply-generic では type-tags が (rectangular)、 proc が rectangular package で定義された magnitude。
グローバルで定義されている magnitude との区別がわかりにくいので、便宜上 rectangular.magnitude としておく。
apply-generic で (rectangular.magnitude (3 . 4)) が呼ばれて無事に 5 が返ってくる。
よって、 apply-generic が呼ばれるのは 2 回。