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言語仕様の上にうまく遅延評価の仕組みを組み入れたライブラリです。







