2010/02/19
マップリテラル
Lispのハッシュテーブルには伝統的にリテラル表記(外部表現)が無い。 他の主要なデータ構造ではread/write invariance (WiLiKi:Scheme:ReadWriteInvariance) が 保証されているので、残念なことである。 ハッシュテーブルは手頃な大きさのマップ(キーから値への写像を表現するデータ構造) に 便利だが、組み込みのマップ型にリテラル表記を備えている言語も増えていて、 Lispに移った時に不便に感じることもある。 (但し、マップを必ずしもハッシュテーブルで実装する必要はない。 Lispの場合、とりあえず読み書きしたかったらalistでいいじゃん、 という要因はあったかもしれない。)
なので、新しいLisp拡張を考える時にハッシュテーブルのリテラル表記を、 と思うのは自然なのだけれど、Common LispやSchemeでハッシュテーブルリテラルが 無いのには理由がある。最大の理由は、 「ハッシュテーブルを再現するには、各要素だけでなくハッシュ関数および比較関数の情報が必要」 という点だろう。
一般的なクロージャのポータブルなリテラル表記は無いので、 これらの関数が自由に指定できる場合、ハッシュテーブルの リテラル表記がいつでも可能とは限らない。 それに関数を書き出せたとしても、 それが人間にとって読み書きしやすいものにはならないかも。 (特に、プログラム中にリテラルとして書きたい場合とか。)
アプリケーションが決まればハッシュ関数と比較関数は固定される ことが多いだろうから、そしたらリードマクロを使って リテラル表現を自由に決めてください、ってのがたぶんCommon Lispの立場。 例えば比較関数をeql決め打ちで
{ :foo => 1 :bar => 2 }
なんてのをハッシュテーブルとして読み込む、とかいうコードはすぐ書ける。
つまり、ハッシュ関数と比較関数が言語で決め打ちになっていれば (たとえカスタマイズできるとしても、大部分のケースをカバーできる関数がデフォルトに なっていれば)、言語としてリテラルを決めてしまってもいい。 マップリテラルがある他の言語は、そういうことだ。 ハッシュ/比較関数の自由度と、リテラルの便利さがトレードオフになっているわけだ。
Lispには比較関数がいくつもあって、これはプログラマの 選択肢をできるだけ用意しとくって精神なんだろうけど、敢えてデフォルトに 絞り込もうとすると「eqかeql」とequalp (Schemeなら「eq?かeqv?」とequal?) が考えられる。 この二つは甲乙つけがたい。基本的に、前者はオブジェクトとしての同一性、 後者は値としての同一性を見ていると考えられるけど、 どちらも同じくらい必要なことが多いからだ。
ところでClojureはマップリテラルを持っている。 その理由は、Clojureではオブジェクトの同一性よりも値の同一性の方が はるかに重要なので、比較関数を = に決め打ちしてしまってもほぼ問題にならないから。 で、なぜ値の同一性の方がそんなに重要になるかというと、 Clojureのデータ構造が原則immutableだから。 immutableなデータ構造では、値の同一性のみが問題になる (メモリ上の同一番地にあろうが別の場所にあろうが、それらのオブジェクトは 操作に対してまったく同様に振る舞うので、区別できない)。
だもんでClojureに関して言えば、データ構造のmutabilityを捨てたら マップリテラルが自然についてきた、という感じだ。
マップリテラルがあるかどうかには、 「等しい」とは何か、という問いが隠されている、という話。 俺言語を設計するときにでも参考にされたし。
Tags: Programming, Lisp
higepon (2010/02/20 16:13:37):
shiro (2010/02/21 09:56:23):
higepon (2010/02/24 02:08:38):
higepon (2010/02/24 02:10:14):
shiro (2010/02/24 08:27:47):
higepon (2010/02/24 12:06:58):