【ちえんひょうか】

遅延評価 とは?

最終更新:
💡 値が必要になるまで、計算を後回しにする

式の値が必要になるまで評価を遅らせる方式。使われない値の計算を省いたり、無限の列から必要な有限部分を扱ったりできる。

📌 このページのポイント
遅延評価と先行評価 同じ計算を、いつ評価するか 先行評価の例 遅延評価の例 引数を先に評価 評価を後回し 評価した値を 関数へ渡す 必要な値を その時点で評価 Haskellの無限の平方数の列 take 5 → [0, 1, 4, 9, 16] 全体を作らず、有限部分を取り出す Promiseの非同期処理とは別の概念
Haskellの無限の平方数から先頭5個を取り出す例。列全体の長さを求めるような処理は終わりません。
ひよこ ひよこ
遅延評価って、計算をサボるってこと?
ペンギン先生 ペンギン先生
式の値が必要になるまで、評価を後回しにすることだよ。不要な値なら評価せずに済む。Haskellでは、使わない引数の計算が終わらなくても、その引数を必要としない関数なら結果を返せる例があるんだ。
ひよこ ひよこ
先に計算する方式とは何が違うの?
ペンギン先生 ペンギン先生
先行評価では、例えば関数へ渡す引数を先に評価してから関数を実行する。遅延評価では、必要な値を求める段階まで評価を遅らせるんだ。コードを定義した瞬間に、書かれた全ての処理が走るかどうか、という区別ではないよ。
ひよこ ひよこ
無限リストを全部メモリに置くの?
ペンギン先生 ペンギン先生
全部を作るわけではないよ。例えばHaskellの無限に続く平方数の列からtake 5で取り出すと、0、1、4、9、16という有限の結果を扱える。一方、無限の列全体の長さを求めるような処理は終わらないんだ。
ひよこ ひよこ
PythonのジェネレーターやPromiseも同じ?
ペンギン先生 ペンギン先生
ジェネレーターは、次の値を求めると実行を再開するので、必要に応じて値を作る例になるよ。ただし式全般の評価方式と同じものではない。JavaScriptのnew Promiseに渡すexecutorは生成時に同期的に呼ばれるので、Promise自体を遅延評価の例にはできないんだ。
ひよこ ひよこ
使えば必ず速くなるの?
ペンギン先生 ペンギン先生
必ずではないよ。不要な評価を省ける一方で、結果をいつ必要とするかによって実行の様子が変わる。無限の列なら有限の部分で処理を終えられるか、エラーがいつ分かるかなども確認しよう。実際の性能は、処理と実装に合わせて測る必要があるね。
ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「遅延評価」って出てきたら「必要になったときだけ計算するしくみ」と思えればだいたいOK!
📖 おまけ:英語の意味
「Lazy Evaluation」 = 怠惰な評価
💬 「Lazy(怠惰な)」という名前は、必要になるまで計算しない「怠け者」な振る舞いから来ているんだよ。対義語は即座に計算する「Eager Evaluation(先行評価)」だよ

参考資料

← 用語集にもどる