Imaginantia

思ったことを書きます

遅延評価のあるべき姿

遅延評価は非常に興味深いシステムではある。普段通り書いた手続き型のプログラムにおける無駄をシステマチックに省くことができる。

が、本当にそんなにも無駄なコードを書くだろうか?

いろんなデータを計算する関数の戻り値の一部しか使わないとして、その残りの部分は計算に不要なものだったのだろうか? もしも不要ならばそれは関連の無い2つの機能をつなげていることにならないだろうか?関連があるとしても一方向ならそれは関数を2つに分解できるはずではないだろうか?

また受けた引数が本質的に計算に不要だというのなら、それは関数の設計が間違っている。 不要なものを渡せないようにし、必要なものだけを返すことは正しい設計だと思う。線形に近い形にもなってくれる。

無限リストはどうだろうか?一度無限の長さを構成し、後に必要な部分だけを切り出す。非常に理にかなったシステムではある。 が、これは遅延評価で実装する必要はまったくない!どうせ headtail でしか値を取り出せないのなら、その関数に対する振る舞いを記述するだけで十分である。(Co-pattern)

話は少しずれるがグラフ簡約はどうなんだろうか。同じ式を持つ値は片方だけを計算すれば良い、ということだが、これは手続き型では当たり前のことである。 同じ式を2回書いた時に自動的に統合してくれるようなシステムはなかなか難しいことが知られているが、一般のプログラマはそのような値は変数として格納することを考えるのではないか。

  • 今思ったけどこういう評価はhashで上手いこと同値性を検出できるんじゃないだろうか。特に結合性や可換性など。

では遅延評価に基づいたデータ構造はどうか?正直これに関しては遅延評価の利点は強く現れているのではないかと思う。 「永続償却 O(1) データ構造」には強い利点がある。が、データ構造をコピーするというのはそこまで多く行われる操作ではないのでは? コピーしてできたもう一つのデータをどう扱うというのだろうか。本当にほしいのはその部分構造のみじゃないのか? 具体例は無いものの、今までC++などでも特に永続データ構造を強く求める声が無いというのはそういうことなのではないか、と思ってしまう。 永続でなければ好きに実装すれば良い。そうなったら遅延評価に勝ち目はない。

今までHaskellで遅延評価に多く苦しめられてきた。私個人の意見としては「デフォルト遅延評価は強すぎる」と感じる。 ただ無限リストのような面白い「概念」としての遅延評価は実際便利である。この辺については副作用の分離が必要となるため綺麗な定義は中々無いが。