Erlangのコレクションと簡易データベース

昨日のエントリー「Erlangのとても困ったところ:単一代入の思わぬ弊害」に、向井淳さんからトラックバックをいただきました。ありがとうございます。

「いー」けど「だめ」

向井さん記事は、Erlangのプロセス・ディクショナリ(プロセスに作り付けのディクショナリ)を使えばスッキリと書けるよ、てな内容。

このようにして書けるのでした。いーでしょ。……だめ?

僕が例として挙げた個別特定具体的なアノ問題に関しては「いー」と思います。が、一般的な文脈では「だめ」です。ディクショナリは、時間的に状態が変化しながらもアイデンティティ(識別性、持続する固有性)を持ち続けるデータの典型例として出したものです。そのディクショナリに関しては、たまたまプロセスに組み込まれたものがあってラッキーですが、他の状態を持つ(かのごとき)データ構造ではどうでしょう。

例えば、gb_setsというライブラリ・モジュールがあります。内部構造に General Balanced Trees を使った順序集合の実装だそうです;マニュアルから抜粋:

An implementation of ordered sets using Prof. Arne Andersson's General Balanced Trees.

使い方は次のようになります。


sample() ->
S0 = gb_sets:new(), % セットを生成
S1 = gb_sets:add_element("板東トン吉", S0), % 要素を追加
S2 = gb_sets:add_element("大垣ペケ子", S1), % さらに要素を追加
gb_sets:is_element("板東トン吉", S2). % 要素かどうか調べる

もちろん、関数呼び出しの入れ子で書いてもいいし、あるいは、リストを作っておいて適当な関数で一括処理という手もあるでしょう。が、いずれの方法もうっとうしく面倒に感じます。

「セットだって、がんばればプロセス・ディクショナリで出来るよ」ってハナシもあるかも知れませんが、じゃあ、モジュールgb_setsは何のために存在しているのでしょう。それを使うのが適切な場面があるからこそgb_setsが提供されているはずです。そもそもモジュールdictも、プロセス・ディクショナリで代替困難/不可能な状況のために準備されているのでしょう。

僕の不満は、「コレクション類など、状態とアイデンティティを持つ(かのごとき)データを扱う記法が不格好でイヤだ、構文糖衣でいいからなんとかしてくれ」ってものです。

有向グラフと組み込み項ストレージ

コレクション類といえば、有向グラフ(directed graph)のモジュールもありました。モジュールdigraphです。ディクショナリやセットと同じ使い勝手かと思ったら:


sample() ->
G = digraph:new(), % グラフを生成
V1 = digraph:add_vertex(G), % 頂点を追加
V2 = digraph:add_vertex(G), % さらに頂点を追加
V3 = digraph:add_vertex(G), % もっと頂点を追加
digraph:add_edge(G, V1, V2, edge1), % 辺を追加
digraph:add_edge(G, V1, V3, edge2), % さらに辺を追加
G. % このグラフを返す
なんか違いますよ。digraph:new()が返すのは、一種の識別子であり、これを第1引数にしていろんな操作をするようになってます。有向グラフはミュータブルみたい。

僕知らなかったんですけど、Erlangランタイムごとに組み込み項ストレージ(Erlang Built-in Term Storage; ETS)というものがあって、簡易データベースのように使えるようです。コマンドets:i().でEシェルからETS状況を確認できます。有向グラフはこのETSにより実装されていたのでした。

ということは、Erlangでコレクション・データ/オンメモリ・ストレージを使いたいときは:

  1. プロセス・ディクショナリ -- お手軽簡単
  2. ライブラリが提供するデータ構造 -- ツリー、セット、ディクショナリなど
  3. 組み込み項ストレージ -- 大容量でミュータブル

といった選択肢があるってことですね。