新しいアカウントで始めました。

身の回りの出来事や写真が中心です。

Rubyをイジって、遊んでました。lazyとは?どんなもんでしょう?

2021-09-20 09:13:07 | Ruby

 lazyでエラーにはなりませんでしたが、効果は分かりません。CreateAry(100)で100個の要素を持つ配列が作られます。この場合のlazyでは、例えば、最初の候補が0でそれを対象にしての処理ではなく、一旦すべての要素の配列を作ってしまいます。それを処理しますので、自分的には0を処理してから、次の1の処理に行くのが、遅延評価と思ってました。

 それを実現することは、可能なんでしょうか?配列を対象にするのが、行けない原因のようにも思えます。

 Pythonのyieldとは、かなり雰囲気が違うようです。遅延評価とは関係無いようです。展開されることと関係してるみたいです。連番から偶数の取り出しを四苦八苦してました。配列のような、実態がハッキリしたものは、分かりやすいですが、実態のないものの処理は、なかなか理解できないですね。


コメント (5)    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ジェネレータ話題は終わりに... | トップ | Rubyで素数のジェネレータ?... »
最新の画像もっと見る

5 コメント

コメント日が  古い順  |   新しい順
lazy evaluation (cametan_42)
2021-09-20 14:18:23
> lazyでエラーにはなりませんでしたが、効果は分かりません。

うん、まぁ、この例だとそうでしょうね。

> 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)させる、ってぇんじゃないと旨味は見えないですね。

もちろん、遅延評価ってそれだけではないんですが、最初に触れる場合、とにかく

「コンピュータで扱う事が不可能な筈の無限長の長さの配列の類」

を扱える楽しさ、ってのを味わうべきだと思いますよ。
もちろんメモリサイズは上限がある筈で、「無限長の長さの配列」なんつーのは扱える筈がないのです。
でも遅延評価だとそれを扱う事が出来る。
その辺の「不思議」っつーか「トリック」ってのが遅延評価の面白さで男のロマンなんです。
返信する
ついでに。 (cametan_42)
2021-09-20 14:32:48
無限長シーケンス

(1..Float::INFINITY)

相手に

(1..Float::INFINITY).select{|x| x % 2 == 0}

なんつーのは危険なんで止めた方が良いと思います
(端末の切り方分かってるのならその限りじゃないですが)
lazyが無ければ全部計算しようとしますが、「無限長」なので計算が終わりません。
要するに無限ループへと突入です。

同様に、

(1..Float::INFINITY).select{|x| x % 2 == 0}.force

もマズい。
この形式でのforceの使い方だと、上と同様に、「全部を実体化(force)」させようとします。
当然、無限長相手に全部実体化させようとすると、無限ループに陥りますね。

とまぁ、無限長シーケンスを扱う時は気をつけましょう。
まぁ、これはこれで一回はやっちゃう、遅延評価でのお楽しみではありますが(笑)。
返信する
訂正 (cametan_42)
2021-09-20 14:35:46
☓ (1..Float::INFINITY).select{|x| x % 2 == 0}.force
○ (1..Float::INFINITY)lazy.select{|x| x % 2 == 0}.force

でしたね、スミマセン。
まぁ下が結果「無限ループ」なんで走らせないに越した事はないわけですけど(笑)。
返信する
cametan_42さん、コメントありがとうございます (isam)
2021-09-20 21:24:51
 今のとこ、暴走させたくないので、確認ですが、(1..Float::INFINITY)を使うときは、lazyとtakeをセットで使うことが必須と言うことですか?
 もしそうなら、確かにlazyが効いてる気がします。takeが無いとすると、無限にすることになるので、やはり、暴走です。
 Cntl+Cで止められるんでしょうか?または、タスクマネージャでかな?
 実際、無限を相手にすることはありませんし、その前に、こっちの命がなくなります。
返信する
lazy (cametan_42)
2021-09-20 22:16:50
> 今のとこ、暴走させたくないので、確認ですが、(1..Float::INFINITY)を使うときは、lazyとtakeをセットで使うことが必須と言うことですか?

はいその通りです。

> もしそうなら、確かにlazyが効いてる気がします。

効いてますね。
まさしくlazyが「遅延評価せよ」と言うコマンドなので。
ある意味、Pythonに比べるとRubyの方がより遅延評価に対応しています。
と言うより、PythonとRubyを比べると、大体に於いて高機能なのはRubyの方ですね。
返信する

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

Ruby」カテゴリの最新記事