SICP §2.4(データ主導プログラミングと加法性 その4[メッセージパッシング])

SCIPに復帰〜♪


このエントリは「メッセージパッシング」についてのお話。
今までは「make-*」系の手続きは、外部から与えられたデータを、consを使って型タグをつけて「データオブジェクト」として保持していた。
今度は、与えられたデータを「手続きオブジェクト」として返し、それに対する操作をその「手続きオブジェクトの中に定義」して管理する方法を紹介する。


まずはコードを紹介。

(define (square x)
  (* x x))

(define (make-from-real-imag x y)
  ;xとyを扱う方法を「手続きオブジェクト」として実装する。
  (define (dispatch op)
    (cond ((eq? op 'real-part)
	   x)
	  ((eq? op 'imag-part)
	   y)
	  ((eq? op 'magnitude)
	   (sqrt (+ (square x) (square y))))
	  ((eq? op 'angle) 
	   (atan y x))
	  (else
	   (error "Unknow op -- MAKE-FROM-REAL-IMAG" op))))
  ;外部からxとyを与えられて生成されたdispatch手続きを返却する。
  ;Lisp/schemeはガーベッジコレクションを標準装備していることになっているため、
  ;外部から渡されたxとyへの参照を、dispatchが保持した形で返却されるため、
  ;xとyは返却されたdispatchがどこからも参照されなくなるまで保持される。
  dispatch)

コードを見ると分かると思うが、使い方はこんな感じになる。


gosh> (define complex1 (make-from-real-imag 2 5))
complex1
gosh> complex1
#
gosh> (complex1 'real-part)
2
gosh> (complex1 'imag-part)
5
gosh> (complex1 'magnitude)
5.385164807134504
gosh> (complex1 'angle)
1.1902899496825317
gosh> (define complex2 (make-from-real-imag 3 4))
complex2
gosh> (complex2 'real-part)
3
gosh> (complex2 'imag-part)
4
gosh> (complex2 'magnitude)
5.0
gosh> (complex2 'angle)
0.9272952180016122
gosh>

生成したデータそのものが手続きであるため、引数に「どのデータを取得したい」という情報を与えてやると、該当するロジックが実行され、お目当てのデータが取得できる感じ。
これを「メッセージパッシング」というらしいよ。