[Gauche-devel-jp] 辞書とイテレータ

アーカイブの一覧に戻る

Shiro Kawai shiro****@lava*****
2003年 1月 20日 (月) 17:42:24 JST


キーから値へのマップを行うフレームワークに関してはずっと頭の隅に
あったのですが、置きっぱなしで埃をかぶっていました。

基本的には議論になっているproceduralなAPIに私も賛成です。

イテレータを用いて(イテレート中の辞書オブジェクトに対する)副作用の
ある操作を行うのは、難しい問題だと思います。iteratee内の副作用に
より、iteratorが保持している内部状態が意味のないものになる可能性
があるからです。

そのため、例えばCommonLispではハッシュテーブルのiterateeが
使える副作用は現在のキーに対するremhashだけ、としたうえ、
さらにiteratorを取り出す with-hash-table-iterator 構文では
iteratorの有効期間をその構文のdynamic extentに明示的に
制限してます。

Gaucheも低レベルではハッシュテーブルの外部iteratorがあるのですが、
それがイテレータループの外に洩れ出すと収拾つかなくなるので、表API
では隠してあります。(Cレベルではiteratorをスタックに置くことで
extentが限られるんで、多少扱い易いのですが)。

で、Gaucheでやるとしたら、やっぱり一連の議論に上がっているように
proceduralなインタフェースにして、かつそのextentを
call-with-iteratorのdynamic extentに制限するのが、まあ一番
妥当かなと思います (extentの制限をかけるとcall/ccを使った
内部イテレータから外部イテレータへの転換の技が使えなくなりますが…)

dynamic extentへの制限が重要なのは、いくつかの副作用については
それが直ちに起こることを保証できないからです。辞書オブジェクトの
実装によっては、副作用は単にキューに貯められていて
call-with-iteratrを抜ける直前にコミットされるかもしれません。
(特に、insertはコミット後に効力を持つと決めておかないとまずい
ですね)。

他のIssueとしては、

 * APIで、渡すprocedureが5つというのはいかにも多すぎますねえ。
   ここまで来たらメッセージでディスパッチするクロージャに
   してしまった方がすっきりするような。
   コレクションフレームワークとの連続性はこの際あまり重要では
   ないでしょう。むしろ辞書フレームワークで良いものが出来たら逆に
   コレクションフレームワークを合わせちゃったっていいし。

 * 中断をどうするか。call/ccでやっても良いのだけれど、どうせ
   iteratee内でnextを呼ばせるんだったら、いっそのこと継続渡しに
   しちまっても良いんじゃないか。つまり、現在位置の値を取り出す
   getメソッドを別に設けて、 nextメソッドを呼ぶこと=続きを
   検索、ということにする。nextメソッドを呼ばなかったらそこで
   iterationはおしまい。

 * もしnextメソッド=継続とするなら、いっそのことfoldみたいな
   インタフェースにして、nextメソッドに値を渡してゆくというのは
   どうか。iterationがおしまいだったらその値がそのままループから
   返される。おしまいで無ければ、iterateeに渡される。

というわけで、こんなのはいかが。

   call-with-iterator (dict <dictionary>) iteratee seed keys ...

で、iterateeは次のように呼ばれる:

   iteratee cursor seed

ここでcursorはprocedureであり、次のような動作をする:

   (cursor 'get)        現在のキーと値を返す。
   (cursor 'next seed) 次にキーとマッチするエントリがあれば、
                        iteratteeを呼び出す。その際にseedを
                        第2引数として渡す。もうマッチするエントリが
                        無ければseedがcall-with-iteratorの
                        戻り値となる。
   (cursor 'update! value) 現在のエントリの値を変更。
   (cursor 'delete!)    現在のエントリを削除。
   (cursor 'insert! key value)   key value ペアを辞書に追加。
                        但し、実際の追加はcall-with-iterator
                        を抜ける直前に行われる。追加されたエントリ
                        に対してiterateeが呼ばれることはない。

seedは最初にiterateeが呼ばれる時はcall-with-iteratorの受け取った
seedで、2回目以降は cursor 'next メソッドに渡された値。

cursorの呼び出しはcall-with-iteratorのdynamic extent内のみで
有効とする。


--shiro


  











Gauche-devel-jp メーリングリストの案内
アーカイブの一覧に戻る