scheme の hashtable について

「データ主導化」のセクションに入ってからの傾向として「実験」をしていない。何故かというと、このテーマを扱う上で肝となる手続きである get 手続きと put 手続きの実装が具体的に定義されてなくて、実行のしようにも不可能だから。


この傾向はまずい。。いや分かっちゃいたんだけどねぇ、最近また風邪ひいたり仕事がアレだったりしてなかなか。。
というわけで、ここで一発、get と put を実際に作っちゃおう!


イメージとしては、hashtable があれば事足りる。こんな感じで。(但し表現の仕方は連想配列になってるけどそこはご愛嬌。)

((type_0 . ((op_0 . (lambda ...))
	    (op_1 . (lambda ...))
	    ...
	    (op_m . (lambda ...))))
 (type_1 . ((op_0 . (lambda ...))
	    (op_1 . (lambda ...))
	    ...
	    (op_m . (lambda ...))))

 ...

 (type_n . ((op_0 . (lambda ...))
	    (op_1 . (lambda ...))
	    ...
	    (op_m . (lambda ...)))))

type_X がキーで、値が op_X のリスト、で、op_Xのリストは更にネストした hashtable の構造を持つ感じ。


hashtable のデータ構造は、今後も頻繁に使うことになるだろう。この際、ここで hashtable についての典型的な使い方をまとめたエントリを作っておくのもいいかもしれない。


つーわけで、これを実現するために必要な手続きを考えていこう。gauche では、hashtable にまつわる手続きとして、これらの手続きが既に用意されている。この中から今回使う手続きをピックアップしておこう。

手続き 概要
(make-hash-table . type) hashtable を生成する。

(オプショナルで、ハッシュコードの比較の方法、type を指定できる。

 eq?、eqv?、equal?、string=? のいずれかを指定し、

 指定しなかった場合は eq? が使用される。
(hash-table-get hashtable key . default) hashtable とキーを指定し、該当するエントリがあればその値を返却する。

(オプショナルで、該当エントリが存在しなかった場合の返却値 default を指定できる。

 指定しなかった場合はエラーを報告する。)
(hash-table-put! hashtable key value) hashtable に対し、keyのエントリの値を value にする。
とりあえずこんだけあれば大丈夫かな。
じゃ、早速 get と put を実装してみよう。

;パッケージのシステムを管理するテーブルを生成
(define package-table (make-hash-table))

;手続きを入れ込む手続き
(define (put operation-symbol type-symbol operation)
  (let ((operations-table (hash-table-get package-table type-symbol #f)))
    (if (eq? #f operations-table)
	;typeが存在しなかった場合は作成しちゃう。
	(let ((tmp (make-hash-table)))
	  (hash-table-put! tmp
			   operation-symbol
			   operation)
	  (hash-table-put! package-table
			   type-symbol
			   tmp))
	;存在した場合はそのテーブルに対して該当する key-value エントリを生成 or 更新
	(hash-table-put! operations-table
			 operation-symbol
			 operation))))

;手続きを取り出す手続き
(define (get operation-symbol type-symbol)
  (let ((operations-table (hash-table-get package-table type-symbol #f)))
    (if (eq? #f operations-table)
	#f
	(hash-table-get operations-table
			operation-symbol
			#f))))

こんな感じか?では実験。


gosh> package-table
gosh> put
gosh> get
gosh> (put 'get-record 'tokyo-db (lambda (key) (print key "で東京のDBから検索されます。")))
#
gosh> (put 'get-record 'osaka-db (lambda (key) (print key "で大阪のDBから検索されます。")))
#
gosh> ((get 'get-record 'tokyo-db) "hogehoge")
hogehogeで東京のDBから検索されます。
#
gosh> ((get 'get-record 'osaka-db) "hogehoge")
hogehogeで大阪のDBから検索されます。
#
gosh>
お〜、いいねぇ。ハッシュテーブル簡単で超便利。