Scheme:ReadWriteInvariance

Scheme:ReadWriteInvariance

Read/Write Invarianceとは

正式な定義は知らないんだけれども、Lisp界隈での使われ方はこんな感じ。

あるオブジェクトをwriteした外部表現を再びreadした時に、元のオブジェクトに 等しい(*)オブジェクトが得られること

この性質があると、評価結果をそのままコピペして別の関数に喰わせられる のでインタラクティブな開発に威力を発揮するほか、途中結果を一時的に ファイルに落としたりネットワーク越しに送ったりすることも簡単にできる。

プログラマにとってもう一つ重要な利点は、 データ構造を手で書き下してみることができることである。 データ構造の設計時のアイディアメモが、そのまま関数に渡せる式に なっているわけだ。また、中間結果として吐き出された式を 手で編集してまたプログラムに喰わせるということも簡単にできる。 これは、メモリ上のデータを直に手でいじっているという感覚を与えてくれる。

Lisperにとってこの性質は空気のようなものなので、この仕組みを実現 するために特別な処理が必要な言語を見ると不思議でならない。

注意すべきところ

但し、全てのオブジェクトに対してread/write invarianceを実現しようと すると、その方法は自明ではない。

まず上の定義における、「等しい」の意味。例えばシンボルはSchemeでは writeしてreadしたら元と eq? なシンボルになるが、コンスセルのような 無名なオブジェクトは読み戻してeq? にするのは困難。一番ゆるい定義は おそらく equal? を採用することだろう。もっとも、Common Lispや (srfi-38を採用した)Schemeでは共有構造や循環構造が表現できるので、 それらを考慮したトポロジカルな相等性 (Gaucheではutil.isomorphのisomorphic?) を考えることが多いと思われる。

また、実行コンテキストの内部情報に依存しない形で書き出すのが困難な 情報をどう扱うかという問題もある。例えばオープン中のネットワーク接続だとか、 継続だとか。Common Lispでは読み込み不可能なオブジェクトをwriteしようと した時にエラーを投げるように設定できる。Schemeの場合、言語仕様では そういう仕組みがないので、頑健性を求める場合は処理系独自の拡張を 使うなり、writeする前に読み込み不可能なオブジェクトが無いかどうかを自分で 確認するなりする必要がある。

浮動小数点数のread/write invarianceについては、Lisp界隈では長く知られて 解決策もある問題である。 (それなのに他の言語実装にあまり広まっていない要素の一つなんじゃないかと思われる)。 浮動小数点数の演算に誤差はつきものだが、計算機内部で表現された 浮動小数点数に関しては、それを10進表記で書き出して再び読み込んだ場合に 正確にもとの数値を得られるような、最短の10進表記を求めるアルゴリズムがある。 (関連: Gauche:数値の入出力, Gauche:拡張浮動小数点演算の謎)。

関連事項

write/read invariance

read/write invarianceと同じ。時系列で言えばwriteしてからread、 なんでこっちの方が自然。でも関数的に (read (write obj)) みたいに考えれば (動くバージョンとしては (read-from-string (write-to-string obj)) か) read/write invarianceの方が自然。

「readしたものをwriteしたら同じ外部表現が得られる」ことは一般に 重視されないので注意。同じオブジェクトに複数の外部表現があり得るので、 このような性質は保証するのが難しい。例えば (a . (b . ())) と (a b) は readしたら共に同じ内部表現になるから、それを区別してwriteすることは不可能である。

write/write invariance

同じオブジェクトを複数回writeした時に、同じ表記が得られるという性質。

オブジェクトを外部的に比較する必要がある場合などに重要になる。

議論、コメント等


古い内容

以下はこのページの古い内容。そのうち整理するので、取っときたい内容は できれば上のページにドキュメントモードで反映して欲しい。

ShiroさんところからR6RS策定絡みで派生した話題

R6RS status report (2005/5)

最初見たときだったのが最後の Consolidation。 comp.lang.scheme でも少し話題になっているようで。

>>>| - all datums will be serializable and obey read/write invariance
>>>I wonder how procedures and open files are going to be serialized.
>
> Unless they change the set of values called datums, procedures
> and ports aren't datums.
>
>> I wonder how the eof-object will be serialized.
>
> My guess: #!eof  (see the previous progress report).

The eof-object isn't a datum either, unless they change the definition of
datum.  See section 7.1.2 of R5RS.

で、datumsっていわゆる値ではないのですね。 procedureが第一級の値で、こいつのことを言っているのだと思ったので、 どうやってR/Wすんだべか???とか真っ先に思ったわけですが、 sec7.1.2に確かに定義されておりますなぁ。 上でもくどくど書かれている通り、datumsの定義が変わってなければ。
結局、read/write invarianceってどういうことよ?ってやっぱり謎。

ここで謎だと発言したのは R5RS の sec7.1.2 に書いてある datum ってのが

<datum> → <simple datum> | <compound datum>
<simple datum> → <boolean> | <number> | <character>
                  | <string> | <symbol>
<compound datum> → <list> | <vector>

となっており、これらが read/write invariance ってのは今も同じではないのか? R6RSでは何が変わろうとしているんだ?というところだ。 ちなみに read/write invariance ってのは R/W 不変性と解釈しており、 要は書き出したものを読み込んだら同じオブジェクト(内部表現)になる ことを保証すること(read back可能な性質)だと思っているのだが。 cut-sea:2005/05/06 04:09:28 PDT

浮動小数点を誤差無く読み書きできるってのが主なんじゃないでしょうか。 あと、シンボルとか。 ひらっち:2005/05/07 16:44:05 PDT

って書いてから思った。浮動小数点を誤差無く読み書きはなさそう。inf とか nan の 話かな。 ひらっち:2005/05/07 16:51:39 PDT

More ...