Enumerable#lazyメソッドとEnumerator::Lazyクラス
前ページの最後の例で、to_a
を付けていたことに気付かれたでしょうか。これを外すと、結果の素数リストではなく何やら妙なオブジェクトが返ってきます。
これは入れ子になったEnumerator::Lazy
クラスのインスタンスです。Enumerable
モジュールをincludeしたクラス(たとえばArray, Hashなど)のインスタンスに対してEnumerable#lazy
メソッドを使うと、Enumerator::Lazy
クラスのオブジェクトが返されます。
Enumerator::Lazy
はEnumerator
のサブクラスとなっています。
Enumerator::Lazy
ではmap, selectといったEnumerator
に属するメソッドがオーバーライドされており、
これらのメソッドを使うと、すぐに結果を返すのではなく「あとでやる処理」として積み重ねられていきます。先の素数100個の例で得られた返り値をもう一度見てみましょう。
まず中心に1..Infinity
のEnumerator::Lazy
オブジェクトがあり、それに対してselect
をかけ、take(100)
しているのがわかります。「あとでやる処理」の予定リストであり、to_a
を付けるとしぶしぶ処理を実行して必要なだけの結果を返していたのです。ちなみにto_a
にはforce
というエイリアスも設定されています。
遅延評価について
このように、必要になるまで処理を実行しない評価手法を「遅延評価」と言います。
Enumerable#lazy を使うと、いままで map でできなかった「無限に続く列」や「巨大な列」、そして「終わりの分からない列」を対象として、map や select などの慣れ親しんだインターフェイスで操作できるようになります。
Enumerator::Lazy
は、既存のRuby言語仕様の上にうまく遅延評価の仕組みを組み入れたライブラリです。