SICP

SICP を読んでみる #72 第二章 p.113

問題解答以前にコードの動作確認ができなくてハマっている問題 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 回。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です