SICP 読み (57) 2.5.1 汎用算術演算

問題 2.77 です。問題の状況を再現してみる。ここでは、p.107 にて提示されている以下の手続きを定義している事を前提に。

(define (real-part z) (apply-generic 'real-part z))
(define (imag-part z) (apply-generic 'imag-part z))
(define (magnitude z) (apply-generic 'magnitude z))
(define (angle z) (apply-generic 'angle z))

で、定義をばくっと gosh に流しこんで以下。

gosh> (install-complex-package)
done
gosh> (install-polar-package)
done
gosh> (install-rectangular-package)
done
gosh> (make-complex-from-real-imag 3 4)
(complex rectangular 3 . 4)
gosh> magnitude 
#<closure magnitude>
gosh> (magnitude (make-complex-from-real-imag 3 4))
*** ERROR: No method for these types -- APPLY-GENERIC (magnitude (complex))
Stack Trace:
_______________________________________
gosh> 

確かに complex なパケジには magnitude なんてインターフェースはないわな。
でも Alyssa さんが言うように単純に complex なパケジにインターフェースを追加して動作するのは何故なんだ、という事を調べてみる。まず動作を。

gosh> (install-complex-package)
done
gosh> (install-polar-package)
done
gosh> (install-rectangular-package)
done
gosh> (make-complex-from-real-imag 3 4)
(complex rectangular 3 . 4)
gosh> magnitude 
#<closure magnitude>
gosh> (magnitude (make-complex-from-real-imag 3 4))
5.0
gosh>

上記の最後の手続きを置き換えてみるか。

(magnitude (make-complex-from-real-imag 3 4))

(magnitude '(complex rectangular 3 . 4))

(apply-generic 'magnitude '(complex rectangular 3 . 4))

(apply (get 'magnitude (map type-tag '((complex rectangular 3 . 4))))
       (map contents '((complex rectangular 3 . 4))))

(apply (get 'magnitude '(complex)) '((rectangular 3 . 4)))

(apply magnitude '((rectangular 3 . 4))) ;; complex の magnitude

(magnitude '(rectangular 3 . 4))

(apply-generic 'magnitude '(rectangular 3 . 4))

(apply (get 'magnitude (map type-tag '((rectangular 3 . 4))))
       (map contents '((rectangular 3 . 4))))

(apply (get 'magnitude '(rectangular)) '((3 . 4)))

(apply magnitude '((3 . 4))) ;; rectangular の magnitude

(sqrt (+ (square (real-part '(3 . 4)))
	 (square (imag-part '(3 . 4)))))

これ、頭の中では考えられんな。てーか、これって継承??
カワを剥いでいく感じがなんか不思議です。

合ってるのかどうか微妙なんで gosh でトレイスしたいんだけど、どうやるんだったか。と言いつつ google 先生に伺ってみると、dankogai さんのエントリが。

で、(use slib) して (require 'trace) すれば良いのね、と言いつつやってみると叱られる。gaunit 使うために testing な debian 使ってるんですが

*** ERROR: unbound variable: slib:features
Stack Trace:
_______________________________________
dpkg: error processing gauche (--configure):
 subprocess post-installation script returned error exit status 1
Errors were encountered while processing:

みたいな感じ。面倒なので chroot じゃない環境でトレイスは確認しよう。

gosh> (magnitude (make-complex-from-real-imag 3 4))
CALL magnitude (complex rectangular 3 . 4)
 CALL magnitude (rectangular 3 . 4)
 RETN magnitude 5.0
RETN magnitude 5.0
5.0
gosh> 

むむ。apply-generic も追加。

gosh> (trace apply-generic)
#<closure 0x850a920(args)>
gosh> (magnitude (make-complex-from-real-imag 3 4))
CALL magnitude (complex rectangular 3 . 4)
 CALL apply-generic magnitude (complex rectangular 3 . 4)
  CALL magnitude (rectangular 3 . 4)
   CALL apply-generic magnitude (rectangular 3 . 4)
   RETN apply-generic 5.0
  RETN magnitude 5.0
 RETN apply-generic 5.0
RETN magnitude 5.0
5.0
gosh> 

合ってるんだと信じたい。(を

追記

置き換えなソレは検証してないな、ということで gosh に吸わせて動作確認してみたんですが、最後のふたつは隠蔽された手続きになるため、gosh 上では確認できず。(当り前か