遅延評価

5.3 遅延評価の利点と欠点

利点について

本書では三つの利点が記されています。
う〜ん、分かったようで分かっていないような感じです。
自分の頭を整理しながら書いていきます。

  • 必要な計算を必要な時に行う点

これは分かりやすいです。不要な計算を省くことで、処理速度は向上するんですね。
C言語などでは、不要な計算をしないようにして処理速度を稼ぎますが、
Haskellでは、自動的にやってくれるんですね。頭いい!


二つ目の利点から、理解が怪しくなっていきます…。

  • 無限のリストが扱える点

たとえば、標準入力を無限リストとして扱う点に関して。


標準入力をリストとして扱う、という動きをC言語で実装する場合、
まぁ、scanf関数やgets関数などを使うことになると思います。
コードで書くとこんな感じかなぁ。

char   buffer[100];
char*  buf = 0;
size_t size = 0;

while(fgets(buffer, 100, stdin)) {

    buf = (char*)realloc(buf, size + 100);

    if(!buf) {
        return 0;
    }

    memcpy(buf + size, buffer, 100);
    size += 100;
}

return buf;


上の例を見ると分かりますが、一度に取得できるものは有限リストです。
ですので、次の入力を取得するために、再度fgets関数を呼び出すことになります。
なお、Enterキーが押されるなどして入力が一度切れたら処理するか、本当に全ての入力を取り込んでから処理するかで
その処理を実行する場所を変える必要があります。


一方Haskellでは、標準入力を無限リストとして扱っているため、自分でリストを構築する必要はありません。
標準入力が無限の長さのリストなので、そこに際限なく標準入力の内容が入ってきます。
上のC言語の例のようにあまり細かく考える必要がありません。
どのタイミングで入力が切れるかとかは一切考える必要はありません。
ただただ、標準入力の内容が全てリストに格納されていると考えちゃっていいわけです。


この差を考えると、無限リストのありがたみが分かるような気がします。
無限リストがあるから、リストを自分で構築するなどの七面倒くさいことをしなくても済むんですね。

どんなに大きなリストでも遅延評価されるため、処理速度をあまり気にせず扱うことが出来る。
というか、逆に遅延評価されるため、全ての操作をリストに統一している、という方が正しいのかな。
たしかに今まで作成してきたHaskellのプログラムは全部リストを扱ったものですね。
何をやるにもリストでやる。この潔さは気持ちいいですね。

5.4 本章のまとめ


この章では練習問題がないんですね!
遅延評価に関して、ほんとに何となくですが理解が深まりました。
というか今までまったく理解出来ていなかったことが改めて分かりました。
C言語などの手続き型言語では、どういった順番で式が評価されるかはもちろん気にしますが、
厳格な規則がありました。どんな時でも適用されるルールがありました。
ですが、Haskell

  • 不要な式は評価されない
  • 式は必要になった時に評価される


という全く違う考え方でした。
C言語とは違うことは分かりますが、この違いの意味はまだきちんと理解出来ていません。
この本を読み終わる頃には分かるようになっていることを期待しつつ次に進みます。