遅延評価の仕組み
必要になったときだけ値を計算します。
「遅延評価の仕組み」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
遅延性とは
Scalaでは、ほとんどの値はstrictです。つまり、定義した瞬間に計算されます。遅延性はこの動作を反転させます。遅延値は、初めて必要になったときにだけ計算され、それより前に計算されることはありません。
これは、計算コストが高い場合、失敗する可能性がある場合、またはまったく使用されない可能性がある場合に重要です。誰も求めていない処理にコストをかける必要があるでしょうか。
Strict val
通常のvalは、右辺をすぐに評価します。その後一度も読み取らない場合でも同じです。
これを実行すると、"computing"が"after"より前に表示されることを確認できます。処理は定義時に実行されます。
object Demo extends App {
val x = { println("computing"); 42 }
println("after")
println(x)
}lazy val
valの前にlazyを付けると、初めてアクセスされるまで評価が延期されます。
ここでは最初に"after"が表示され、その後xを読み取ったときだけ"computing"が表示されます。結果もキャッシュされるため、本体が実行されるのは最大1回です。
object Demo extends App {
lazy val x = { println("computing"); 42 }
println("after")
println(x)
println(x)
}名前渡しパラメーター
=> Aとして宣言されたパラメーターは名前渡しで渡されます。つまり、引数はメソッド内で使用されるまで評価されません。
これは遅延性の基盤となる仕組みです。LazyListは名前渡しパラメーターを使用するため、要求されるまで末尾が計算されません。
def maybe(cond: Boolean, value: => Int): Int =
if (cond) value else 0
val r = maybe(false, { println("side"); 99 })
// "side" never prints; value was unusedLazyListの概要
LazyListはScalaの遅延シーケンスです(2.13以降では以前のStreamに置き換わりました)。先頭は即時評価されますが、末尾は遅延評価されます。
要素は必要に応じて生成され、計算後に一度だけメモ化されるため、同じセルが2回計算されることはありません。
val ll = LazyList(1, 2, 3)
println(ll)
// prints LazyList(<not computed>) until forced評価の強制
LazyListは、評価を強制するまで未評価のままです。toListやforeachを呼び出したり、各要素を表示したりすると、セルの評価が強制されます。
REPLでは、遅延している末尾に<not computed>と表示されます。評価を強制すると実際の値が現れます。
object Demo extends App {
val ll = LazyList(1, 2, 3)
println(ll.toList)
}#::演算子
#::を使うとLazyListの先頭に要素を追加できます。リストの::とは異なり、#::の右オペランドは名前渡しであるため、必要になるまで末尾は構築されません。
これにより、残りの部分を遅延的に計算するシーケンスを記述できます。
val ll = 1 #:: 2 #:: 3 #:: LazyList.empty
println(ll.head)メモ化
LazyListのセルが一度計算されると、その値が保存されます。もう一度読み取ってもコストはかからず、生成元の式が再度実行されることもありません。
これを実行すると、"calc"は各要素に初めてアクセスしたときだけ表示され、繰り返し読み取っても表示されないことを確認できます。
object Demo extends App {
val ll = LazyList(1, 2).map { n =>
println("calc " + n); n * 10
}
println(ll.head)
println(ll.head)
}遅延する末尾の動作
末尾が遅延するため、LazyListにmapを適用しても、実際にアクセスした要素だけが計算されます。
ここではリストに3つの要素があるにもかかわらず、強制されるのが先頭だけなので、"map"は1回だけ表示されます。
object Demo extends App {
val r = LazyList(1, 2, 3).map { n =>
println("map " + n); n + 1
}
println(r.head)
}遅延性の利点
遅延性には、不要な処理を避けること、無限シーケンスを構築すること、計算の記述方法と実行量を切り離すことという3つの利点があります。
パイプライン全体を一度記述し、何個の要素を取得するかは利用側に決めさせることができます。
注意点
遅延性にはコストもあります。LazyListはメモ化するため、先頭への参照を保持すると、強制評価されたすべての要素がメモリに残り続けます。巨大なデータや無限データでは、先頭を保持し続けないようにしてください。
また、遅延コード内の副作用は予期しないタイミングで実行されるため、デバッグを難しくすることがあります。
理解度チェック
遅延評価についての理解度を確認してください。
まとめ
厳格評価では処理がすぐに実行され、遅延評価では必要になるまで延期されます。lazy valと名前渡しパラメーター(=> A)が基本となる仕組みです。
LazyListはこれらを基盤として、即時評価される先頭と、遅延評価されてメモ化される末尾を構築します。評価はtoListや要素へのアクセスによって強制されます。次は、LazyListを手作業で構築します。
よくある質問
「遅延評価の仕組み」レッスンは無料ですか?
はい。「遅延評価の仕組み」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
「遅延評価の仕組み」で何を学びますか?
必要になったときだけ値を計算します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「遅延評価の仕組み」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?
はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。