lazyでエラーにはなりませんでしたが、効果は分かりません。CreateAry(100)で100個の要素を持つ配列が作られます。この場合のlazyでは、例えば、最初の候補が0でそれを対象にしての処理ではなく、一旦すべての要素の配列を作ってしまいます。それを処理しますので、自分的には0を処理してから、次の1の処理に行くのが、遅延評価と思ってました。
それを実現することは、可能なんでしょうか?配列を対象にするのが、行けない原因のようにも思えます。
Pythonのyieldとは、かなり雰囲気が違うようです。遅延評価とは関係無いようです。展開されることと関係してるみたいです。連番から偶数の取り出しを四苦八苦してました。配列のような、実態がハッキリしたものは、分かりやすいですが、実態のないものの処理は、なかなか理解できないですね。
はいその通りです。
> もしそうなら、確かにlazyが効いてる気がします。
効いてますね。
まさしくlazyが「遅延評価せよ」と言うコマンドなので。
ある意味、Pythonに比べるとRubyの方がより遅延評価に対応しています。
と言うより、PythonとRubyを比べると、大体に於いて高機能なのはRubyの方ですね。
もしそうなら、確かにlazyが効いてる気がします。takeが無いとすると、無限にすることになるので、やはり、暴走です。
Cntl+Cで止められるんでしょうか?または、タスクマネージャでかな?
実際、無限を相手にすることはありませんし、その前に、こっちの命がなくなります。
○ (1..Float::INFINITY)lazy.select{|x| x % 2 == 0}.force
でしたね、スミマセン。
まぁ下が結果「無限ループ」なんで走らせないに越した事はないわけですけど(笑)。
(1..Float::INFINITY)
相手に
(1..Float::INFINITY).select{|x| x % 2 == 0}
なんつーのは危険なんで止めた方が良いと思います
(端末の切り方分かってるのならその限りじゃないですが)
lazyが無ければ全部計算しようとしますが、「無限長」なので計算が終わりません。
要するに無限ループへと突入です。
同様に、
(1..Float::INFINITY).select{|x| x % 2 == 0}.force
もマズい。
この形式でのforceの使い方だと、上と同様に、「全部を実体化(force)」させようとします。
当然、無限長相手に全部実体化させようとすると、無限ループに陥りますね。
とまぁ、無限長シーケンスを扱う時は気をつけましょう。
まぁ、これはこれで一回はやっちゃう、遅延評価でのお楽しみではありますが(笑)。
うん、まぁ、この例だとそうでしょうね。
> CreateAry(100)で100個の要素を持つ配列が作られます。
そう、有限個の、上限がある配列相手だとそうなるでしょう。
仮に有限個でも、100,000個とか1,000,000個とかの配列でもないとありがたみがないかも。
いや、今のPCだとかなり速いんで、それでもありがたくないかもしれません。
Lazy Evaluationが英語での「遅延評価」なので、lazyはまさしく、Rubyの遅延評価の為の機構です。
その前に無限長の長さを持つ配列モドキの作り方、から。
Rubyだと次のように表記します。
irb(main):001:0> (1..Float::INFINITY)
=> 1..Infinity
何故にFloatなのかはちと謎なのですが、いずれにせよ、INFINITYは無限大の事なんで、まさしくケツが無限大のオブジェクトです。
で、悪いんですが、これってこのまま使えるわけですよ。わざわざCreateArrayってメソッドを作らなくて良いわけです。
irb(main):002:0> (1..Float::INFINITY).lazy.select{|x| x % 2 == 0}.take(6).force
=> [2, 4, 6, 8, 10, 12]
無限長の長さからアタマ6つ持ってきて実体化(force)させる、ってぇんじゃないと旨味は見えないですね。
もちろん、遅延評価ってそれだけではないんですが、最初に触れる場合、とにかく
「コンピュータで扱う事が不可能な筈の無限長の長さの配列の類」
を扱える楽しさ、ってのを味わうべきだと思いますよ。
もちろんメモリサイズは上限がある筈で、「無限長の長さの配列」なんつーのは扱える筈がないのです。
でも遅延評価だとそれを扱う事が出来る。
その辺の「不思議」っつーか「トリック」ってのが遅延評価の面白さで男のロマンなんです。