SlideShare a Scribd company logo
1 of 16
Download to read offline
Enumerable#lazyについて

      2012/11/10
        cuzic
Ruby 2.0.0 について                        1
 Ruby の生誕20周年にリリース予定
     2013年2月24日 公式リリース予定
 新機能
     実はそれほど多くない
     100%互換を目指している
     大きいのは、パラメータ引数 と Module#prepend くらい?
 Enumerable#lazy
     Ruby 2.0.0 の新機能の1つ
     遅延評価っぽい配列演算を扱うことができるライブラリ
     Esoteric Lang や Ruby ISO 界隈で有名な @yhara さんの作




2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
Enumerable#lazy                                      2
  Enumerable#lazy を使うと、"遅延評価" される
  ふつうにやると、無限ループになっちゃってハマる
  Enumerable#lazy があれば、必要な分を1個ずつ処理する。
      無限個のリストでも問題なく処理できる。


■ 1,000 より大きな素数を 10個 出力する                 ■ 1,000 より大きな素数を 10個 出力する
  無限ループに陥る                                  最初の 10個だけが処理される
require 'prime'                           require 'prime'

infinity = 1.0/0                          infinity = 1.0/0
(1000..infinity).select do |i|            (1000..infinity).lazy.select do |i|
  i.prime?                                  i.prime?
end. # ここで、無限ループに陥る                       end.take(10). # 最初の10個だけを評価する
  take(10).each do |i|                      each do |i|
  puts i                                    puts i
end                                       end




  2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
Enumerable#lazy のベンリなところ                                        3
【Enumerable#lazy を使わなければ】                【Enumerable#lazy なら】
 (1) map などの処理ごとに配列を生成する                  (1) map などの処理ごとに、
   ・大量の配列生成をともなうので、                           Enumerator::Lazy オブジェクトを生成
     メモリ効率が悪い                               ・すべての要素を配列にしたりしない
 (2) 最終的に使われなくても、生成する                       ・大量のメモリを消費したりしない
   ・もったいない                                (2) 次に使う分だけ生成する
   ・下の例だと、10個目より後は不要                        ・エコ
 (3) 無限ループに陥る                               ・下の例だと、10個目より後は何もしない
   ・無限個の要素を処理しようとするので                     (3) 無限を無限のまま扱える
     無限ループになっちゃう。                           ・宇宙ヤバい

■ 1,000 より大きな素数を 10個                      ■ ".rb" ファイルを 10個 列挙
require 'prime'                           require 'find'

infinity = 1.0/0                          Find.find("/").lazy.select do |f|
(1000..infinity).lazy.select do |i|         File.file?(f) && f.end_with?(".rb")
  i.prime?                                end.take(10).each do |f|
end.take(10). # 最初の10個だけを評価する               puts f
  each do |i|                             end
  puts i
end

  2012/11/10 Scala/Clojure/Ruby勉強会    「Enumerable#lazy について」
Enumeratable#lazy の内部動作(1)                        4
 Enumerable#lazy は Enumerator::Lazy オブジェクトを返す
     Enumerator::Lazy は Enumerator のサブクラス
     Enumerator : 外部イテレータを実現するためのクラス
     内部では Fiber を使って実装されている
 Enumerator::Lazy は、Enumerable モジュールのメソッドを再定義
    map 、select、take などのメソッドの返り値は、Enumerator::Lazy オブジェクト
  ※ Enumerable モジュールで増えるメソッドは Enumerable#lazy だけ。


                          ここで、Enumerator::Lazy オブジェクトを生成。
infinity = 1.0/0
(1000..infinity).lazy.
                          1個ずつ処理する。
  select do |i|
  i.prime?                select や take などの Enumerable モジュールのメソッド
end.                      は、Enumerator::Lazy クラスでは
  take(10).each do |i|
  puts i                  1個ずつ処理する Enumerator::Lazy オブジェクト
end                       を返すように再定義されている。




2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
Enumerable#lazy の内部動作(2)                                       5
 Enumerable#lazy は最初の1個だけがんばって処理。残りは後回し。
     2個目以降については、後工程で必要になって初めて、前工程の処理を行う。



                                                inf = 1.0/0
                                                (1000..inf).lazy.select do |i|
【lazy Fiber】 (1000..inf).lazy
                                                  i.prime?
値を順に yield する Enumerable::Lazy オブジェクトを生成
                                                end.take(10). # 最初の10個だけ評価
次の値を yield して、 lazy Fiber は中断する。
                                                  each do |i|
                                                    puts i
     【select Fiber】 select {|i| i.prime?}         end
     素数である場合だけ yield する E::Lazy オブジェクト
     素数となる値が来るまで、親 Fiber に値を要求する。
     素数があれば、その値を yield して select Fiber は中断

          【take Fiber】 take(10)
          最初の 10個であれば yield する E::Lazy オブジェクト
          親 Fiber から得られた値を 10個目までは 子Fiber に
          そのまま yield し、take Fiber は処理を中断する。

               【each Fiber】 each {|i| puts i }
               親Fiber から受け取った値をそのまま 表示する。
               ループごとに親 Fiber に次の値を要求する。

 2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
Enumerator の復習                                         6
 Enumerator                            ■ Object#enum_for による Enumerator の生成

     Enumerable なオブジェクト                enum = "abc".enum_for(:each_byte)
                                       enum.each do |byte|
     を簡単に作れる                             puts byte
     ~Ruby 1.8.6 の標準添付ライブラリ            end
     Ruby 1.8.7 の組込ライブラリ
                                       ■ Enumerator.new による Enumerator の生成
     Enumerable::Enumerator
     Ruby 1.8.8~ の組込ライブラリ              str = "abc"
                                       enum = Enumerator.new(str, :each_byte)
     Enumerator
                                       enum.each do |byte|
     Ruby 1.9 で Generator の機能を           puts byte
     取り込み強化される                         end

■ Ruby 1.8 の添付ライブラリ Generator          ■ Enumerator.new (Ruby 1.9 feature )
g = Generator.new do |yielder|         enum = Enumerator.new do |yielder|
  "abc".each_byte do |byte|              "abc".each_byte do |byte|
    yielder.yield byte                     yielder << byte
  end                                    end
end                                    end
# callcc だから遅い                         # Fiber を使っているから速い
g.each do |byte|                       enum.each do |byte|
  puts byte                              puts byte
end                                    end

2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
Enumerator と Fiber                              7
  Enumerator は Fiber を活用するデザインパターンの1つ
      Fiber における難しい概念を隠ぺい
      Fiber.yield => Enumerator::Yielder#<< 、 Enumerator#each による列挙
  Enumerator を使いこなせれば、十分 Fiber のメリットを活用できる
  《参考: Fiber にできて、Enumerator でできないこと》
   親 Fiber から 子Fiber へのデータの送付(Fiber.yield の返り値の利用)
■ Enumerator の例(フィボナッチ数)                    ■ 《参考》 Fiberの例(フィボナッチ数)
fib = Enumerator.new do |yielder|           fib = Fiber.new do
  a = b = 1                                   a = b = 1
  loop do                                     loop do
                                                Fiber.yield a
    yielder << a
                                                a, b = b, a + b
    a, b = b, a + b                           end
  end                                       end
end
                                            def fib.each
fib.each do |i|                               loop do              これが必要。
                        Enumerator の
  break if i > 1000     内部実装まで
                                                yield fib.resume   だけど、これが
                                              end
  puts i
                        考えなくていい             end                    難しい。(汗)
end
                                            fib.each do |i|
                                              break if i > 1000
                                              puts i
                                            end
  2012/11/10 Scala/Clojure/Ruby勉強会     「Enumerable#lazy について」
Enumerator はベンリ                                    8
  Enumerator なら Enumerable の便利メソッドを使える。
      ブロック付メソッド呼び出しは単純なイテレーションならいいけど。。。
  Enumerator はオブジェクトなので、使い回しが簡単。
      引数にしたり、返り値にしたり、インスタンス変数に格納したり
      Enumerator オブジェクトの生成も慣れれば簡単。

■ Enumerator の例(フィボナッチ数)                  ■ 《参考》 ブロック付メソッド呼び出しの例
fib = Enumerator.new do |yielder|         def fibonacci
  a = b = 1                                 a = b = 1
  loop do                                   loop do
    yielder << a          慣れれば、               yield a
    a, b = b, a + b       カンタン                a, b = b, a + b
  end                                       end
end                                       end
fib.each do |i|                           fibonacci do |i|
  break if i > 1000                         break if i > 1000
  puts i                                                          単純なイテレーション
end                                         puts i                ならいいけど・・・。
                                          end
fib.each_cons(2) do |i, j|   Enumerable
  break if i > 1000                       prev = nil
                             の便利メソッド      fibonacci do |i|
  puts "#{i} #{j}"           を使い放題
end                                         break if i > 1000             面倒 ! !
                                            puts "#{prev} #{i}" if prev
                                            prev = i
                                          end
  2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
(おまけ) Enumerator の利用例
データ構造に対する巡回方法を Enumerator で抽象化可能
                                          1       2           3                  1     4           7
マトリックスに対して、
行 => 列 の順で列挙するか                           4       5           6                  2     5           8
列 => 行 の順で列挙するか
                                          7       8           9                  3     6           9

                                                                  /       ①

                                   /bin                /usr               /etc         /home
                                          ②                   ③                  ④             ⑤

 木構造に対して、                                 /usr/local
                                                       ⑥
                                                              /usr/lib
                                                                         ⑦
                                                                                     /home/cuzic
                                                                                       ⑧
 幅優先探索を行うか
 深さ優先探索を行うか
                                                                  /
                                                                         ①

                                   /bin                /usr               /etc         /home
                                          ②                   ③                  ⑥             ⑦
                                          /usr/local          /usr/lib               /home/cuzic
                                                   ④                  ⑤               ⑧
2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
Enumerable#lazy の実装                                             10
  Enumerable#lazy を使うと、Enumerable のメソッドの返り値が
  Enumerator::Lazy オブジェクトになる
  Enumerable モジュールに増やすメソッドは Enumerable#lazy だけ
module Enumerable                                  def select(&block)
  def lazy                                           Lazy.new(self){|yielder, val|
    Enumerator::Lazy.new(self)                         if block.call(val)
  end                                                    yielder << val
end                                                    end
                                                     }
class Enumerator                                   end
  class Lazy < Enumerator
    def initialize(obj, &block)
                                                   def take(n)
      super(){|yielder|
                                                     taken = 0
        begin
                                                     Lazy.new(self){|yielder, val|
          obj.each{|x|
            if block                                   if taken < n
              block.call(yielder, x)                     yielder << val
            else                                         taken += 1
              yielder << x                             else
            end                                          raise StopIteration
          }                                            end
        rescue StopIteration                         }
        end                                        end
      }                                       ……
    end                                     end

  2012/11/10 Scala/Clojure/Ruby勉強会     「Enumerable#lazy について」
Enumerable#lazy の活用例                                          11
    Enumerable#lazy を上手に活用すると生成、フィルタを順に
    処理するプログラムをメソッドチェーンで簡潔に記述できる。
require 'forwardable'                    def map &block
                                           @lazy = @lazy.map &block
class FizzBuzz                             self
  extend Forwardable                     end
  def_delegators :@lazy, :each           def fizzbuzz
                                           map do |i|
 def self.each &blk                            (i % 15 == 0) ? "FizzBuzz" : i
   fb = self.new                           end
   fb.fizzbuzz.fizz.buzz.                end
     take(30).each(&blk)                 def buzz
 end                                       map do |i|
                                               (i % 5 == 0) ? "Buzz" : i
 def initialize                            end
   inf = 1.0/0                           end
   @lazy = (1..inf).lazy                 def fizz
 end                                       map do |i|
                                               (i % 3 == 0) ? "Fizz" : i
 def take n                                end
   @lazy = @lazy.take n                  end
   self                                end
 end                                   FizzBuzz.each do |i|
                                         puts i
                                       end
2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
(おまけ)パイプライン処理                                               12
    Enumerator を活用すると、UNIX のパイプのように処理を書ける
        下記の例では本当にパイプ(|)で処理する例
        ついカッとなってやった。今は反省している。
    ふつうはメソッドチェーンで十分実用的
        フィルタ処理をオブジェクトにしたいときはこういう方法もベンリかも。
        Enumerator.new の書き方に精通していないと、分かりにくい。。。
            Enumerable#map とか使って、書けたら分かりやすいのにな。。。
      # Enumerable#lazy は無関係だけど。。。



class Pipeline <Enumerator
  attr_accessor :source                     def main
  def |(other)                                fb    = FizzBuzz.new(15, "FizzBuzz")
    other.source = self                       buzz = FizzBuzz.new( 5, "Buzz")
    other                                     fizz = FizzBuzz.new( 3, "Fizz")
  end
end                                           inf   = 1.0/0
                                              sink = Pipeline.new(1..inf)
class FizzBuzz <Pipeline                      pipe = sink | fb | buzz | fizz
  def initialize n, subst                     pipe.take(30).each{|i| puts i}
    super() do |y|
      @source.each do |i|                   end
        y << (i % n == 0) ? subst : i
      end                                   if $0 == __FILE__
    end                                       main
  end                                       end
end
2012/11/10 Scala/Clojure/Ruby勉強会        「Enumerable#lazy について」
(おまけ) もっと lazy に                                     13
      クロージャを活用すれば、もっと評価タイミングを遅延できる
      値ではなく、クロージャを要素とし、必要なときクロージャを評価する
      クロージャなら、memoize も簡単に実装可能
          同じ計算を2回以上しないようにできる。
     # 下記の例も Enumerable#lazy と関係ない。。。

# memoize しない場合。同じ計算を何度もする。               # memoize版。同じ計算は1度だけ。圧倒的に速い。
# すごい遅い。                                  def add a, b
                                            memo = nil
def add a, b                                lambda do
  lambda do                                   return memo if memo
    return a.() + b.()                        memo = a.() + b.()
  end                                         return memo
end                                         end
                                          end
fib = Enumerator.new do |yielder|
  a = b = lambda{ 1 }                     fib = Enumerator.new do |yielder|
  loop do                                   a = b = lambda{ 1 }
    yielder << a                            loop do
    a, b = b, add(a, b)                       yielder << a
  end                                         a, b = b, add(a, b)
end                                         end
                                          end
fib.take(36).each do |i|
  puts i.()                               fib.take(36).each do |i|
end                                         puts i.()
                                          end
  2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
まとめ                      14
 Enumerable#lazy
     @yhara さんの作品
     無限を無限のまま扱える
     次の1個だけ処理して、残りは後回し
         全部一気に処理するより、必要なメモリ量が少なくて済む
 Enumerator
     Enumerator::Lazy の内部実装で大活躍
     Enumerator は Fiber より分かりやすく、実用的。
         Fiber でやりたいことの大部分は Enumerator で十分可能
 発展的な使い方
   メソッドチェーンでパイプライン処理とか
   クロージャを使ってより遅延評価させたり。




2012/11/10 Scala/Clojure/Ruby勉強会   「Enumerable#lazy について」
15




ご清聴ありがとう
 ございました

More Related Content

What's hot

FINAL FANTASY Record Keeper の作り方
FINAL FANTASY Record Keeper の作り方FINAL FANTASY Record Keeper の作り方
FINAL FANTASY Record Keeper の作り方dena_study
 
Apache Avro vs Protocol Buffers
Apache Avro vs Protocol BuffersApache Avro vs Protocol Buffers
Apache Avro vs Protocol BuffersSeiya Mizuno
 
イベント・ソーシングを知る
イベント・ソーシングを知るイベント・ソーシングを知る
イベント・ソーシングを知るShuhei Fujita
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門Takuya Kitamura
 
なぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのかなぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのかYoichi Toyota
 
2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする
2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする
2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りするYuichiro Yamashita
 
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割Recruit Lifestyle Co., Ltd.
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All ThingsUnityTechnologiesJapan002
 
JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用
JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用
JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用Akinori SAKATA
 
いまさら、AWSのネットワーク設計
いまさら、AWSのネットワーク設計いまさら、AWSのネットワーク設計
いまさら、AWSのネットワーク設計Serverworks Co.,Ltd.
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とdo_aki
 
JenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudy
JenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudyJenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudy
JenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudyKazuhito Miura
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
急速に進化を続けるCNIプラグイン Antrea
急速に進化を続けるCNIプラグイン Antrea 急速に進化を続けるCNIプラグイン Antrea
急速に進化を続けるCNIプラグイン Antrea Motonori Shindo
 
PHP7の内部実装から学ぶ性能改善テクニック
PHP7の内部実装から学ぶ性能改善テクニックPHP7の内部実装から学ぶ性能改善テクニック
PHP7の内部実装から学ぶ性能改善テクニックYoshio Hanawa
 
ZabbixのAPIを使って運用を楽しくする話
ZabbixのAPIを使って運用を楽しくする話ZabbixのAPIを使って運用を楽しくする話
ZabbixのAPIを使って運用を楽しくする話Masahito Zembutsu
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなKentaro Matsui
 
エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得Reimi Kuramochi Chiba
 

What's hot (20)

FINAL FANTASY Record Keeper の作り方
FINAL FANTASY Record Keeper の作り方FINAL FANTASY Record Keeper の作り方
FINAL FANTASY Record Keeper の作り方
 
Apache Avro vs Protocol Buffers
Apache Avro vs Protocol BuffersApache Avro vs Protocol Buffers
Apache Avro vs Protocol Buffers
 
イベント・ソーシングを知る
イベント・ソーシングを知るイベント・ソーシングを知る
イベント・ソーシングを知る
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門
 
なぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのかなぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのか
 
2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする
2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする
2022/4/15_(DDD) Kotlin 1.5 で stable になった value class を深掘りする
 
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
 
JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用
JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用
JaSST Tokyo 2022 アジャイルソフトウェア開発への統計的品質管理の応用
 
いまさら、AWSのネットワーク設計
いまさら、AWSのネットワーク設計いまさら、AWSのネットワーク設計
いまさら、AWSのネットワーク設計
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
 
JenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudy
JenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudyJenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudy
JenkinsとDockerって何が良いの? 〜言うてるオレもわからんわ〜 #jenkinsstudy
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
急速に進化を続けるCNIプラグイン Antrea
急速に進化を続けるCNIプラグイン Antrea 急速に進化を続けるCNIプラグイン Antrea
急速に進化を続けるCNIプラグイン Antrea
 
PHP7の内部実装から学ぶ性能改善テクニック
PHP7の内部実装から学ぶ性能改善テクニックPHP7の内部実装から学ぶ性能改善テクニック
PHP7の内部実装から学ぶ性能改善テクニック
 
ZabbixのAPIを使って運用を楽しくする話
ZabbixのAPIを使って運用を楽しくする話ZabbixのAPIを使って運用を楽しくする話
ZabbixのAPIを使って運用を楽しくする話
 
Railsで作るBFFの功罪
Railsで作るBFFの功罪Railsで作るBFFの功罪
Railsで作るBFFの功罪
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
 
Zabbix概論2018
Zabbix概論2018Zabbix概論2018
Zabbix概論2018
 
エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得
 

More from Tomoya Kawanishi

ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例Tomoya Kawanishi
 
エンジニア転職のノウハウ
エンジニア転職のノウハウエンジニア転職のノウハウ
エンジニア転職のノウハウTomoya Kawanishi
 
Ruby の文字列について
Ruby の文字列についてRuby の文字列について
Ruby の文字列についてTomoya Kawanishi
 
Ruby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構についてRuby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構についてTomoya Kawanishi
 
Ruby初心者からよく質問されること
Ruby初心者からよく質問されることRuby初心者からよく質問されること
Ruby初心者からよく質問されることTomoya Kawanishi
 
RubyGems と Bundler について
RubyGems と Bundler についてRubyGems と Bundler について
RubyGems と Bundler についてTomoya Kawanishi
 
Ruby の正規表現について
Ruby の正規表現についてRuby の正規表現について
Ruby の正規表現についてTomoya Kawanishi
 
Ruby での外部コマンドの実行について
Ruby での外部コマンドの実行についてRuby での外部コマンドの実行について
Ruby での外部コマンドの実行についてTomoya Kawanishi
 
Ruby のワンライナーについて
Ruby のワンライナーについてRuby のワンライナーについて
Ruby のワンライナーについてTomoya Kawanishi
 
AWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったことAWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったことTomoya Kawanishi
 
PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選Tomoya Kawanishi
 
HTTPと Webクローリングについて
HTTPと WebクローリングについてHTTPと Webクローリングについて
HTTPと WebクローリングについてTomoya Kawanishi
 
Active record query interface
Active record query interfaceActive record query interface
Active record query interfaceTomoya Kawanishi
 
Active Support のコア拡張機能について
Active Support のコア拡張機能についてActive Support のコア拡張機能について
Active Support のコア拡張機能についてTomoya Kawanishi
 
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナーRuby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナーTomoya Kawanishi
 
RubyのDir、File、IO について
RubyのDir、File、IO についてRubyのDir、File、IO について
RubyのDir、File、IO についてTomoya Kawanishi
 
Thread の利用事例紹介
Thread の利用事例紹介Thread の利用事例紹介
Thread の利用事例紹介Tomoya Kawanishi
 
Ruby の制御構造とリテラルについて
Ruby の制御構造とリテラルについてRuby の制御構造とリテラルについて
Ruby の制御構造とリテラルについてTomoya Kawanishi
 

More from Tomoya Kawanishi (20)

英単語の覚え方
英単語の覚え方英単語の覚え方
英単語の覚え方
 
ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例ENECHANGE社での Scout APM 利用事例
ENECHANGE社での Scout APM 利用事例
 
エンジニア転職のノウハウ
エンジニア転職のノウハウエンジニア転職のノウハウ
エンジニア転職のノウハウ
 
Ruby の文字列について
Ruby の文字列についてRuby の文字列について
Ruby の文字列について
 
Ruby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構についてRuby on Rails のキャッシュ機構について
Ruby on Rails のキャッシュ機構について
 
Ruby初心者からよく質問されること
Ruby初心者からよく質問されることRuby初心者からよく質問されること
Ruby初心者からよく質問されること
 
RubyGems と Bundler について
RubyGems と Bundler についてRubyGems と Bundler について
RubyGems と Bundler について
 
Ruby の正規表現について
Ruby の正規表現についてRuby の正規表現について
Ruby の正規表現について
 
Ruby での外部コマンドの実行について
Ruby での外部コマンドの実行についてRuby での外部コマンドの実行について
Ruby での外部コマンドの実行について
 
Ruby のワンライナーについて
Ruby のワンライナーについてRuby のワンライナーについて
Ruby のワンライナーについて
 
AWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったことAWS のコスト管理をちゃんとしたくてやったこと
AWS のコスト管理をちゃんとしたくてやったこと
 
PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選PostgreSQL のイケてるテクニック7選
PostgreSQL のイケてるテクニック7選
 
HTTPと Webクローリングについて
HTTPと WebクローリングについてHTTPと Webクローリングについて
HTTPと Webクローリングについて
 
Rake
RakeRake
Rake
 
Active record query interface
Active record query interfaceActive record query interface
Active record query interface
 
Active Support のコア拡張機能について
Active Support のコア拡張機能についてActive Support のコア拡張機能について
Active Support のコア拡張機能について
 
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナーRuby ビジネス創出展 Ruby初心者向けプログラミングセミナー
Ruby ビジネス創出展 Ruby初心者向けプログラミングセミナー
 
RubyのDir、File、IO について
RubyのDir、File、IO についてRubyのDir、File、IO について
RubyのDir、File、IO について
 
Thread の利用事例紹介
Thread の利用事例紹介Thread の利用事例紹介
Thread の利用事例紹介
 
Ruby の制御構造とリテラルについて
Ruby の制御構造とリテラルについてRuby の制御構造とリテラルについて
Ruby の制御構造とリテラルについて
 

Recently uploaded

業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video UnderstandingToru Tamaki
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Gamesatsushi061452
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...Toru Tamaki
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Hiroshi Tomioka
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 

Recently uploaded (11)

業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 

Enumerable lazy について

  • 1. Enumerable#lazyについて 2012/11/10 cuzic
  • 2. Ruby 2.0.0 について 1 Ruby の生誕20周年にリリース予定 2013年2月24日 公式リリース予定 新機能 実はそれほど多くない 100%互換を目指している 大きいのは、パラメータ引数 と Module#prepend くらい? Enumerable#lazy Ruby 2.0.0 の新機能の1つ 遅延評価っぽい配列演算を扱うことができるライブラリ Esoteric Lang や Ruby ISO 界隈で有名な @yhara さんの作 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 3. Enumerable#lazy 2 Enumerable#lazy を使うと、"遅延評価" される ふつうにやると、無限ループになっちゃってハマる Enumerable#lazy があれば、必要な分を1個ずつ処理する。 無限個のリストでも問題なく処理できる。 ■ 1,000 より大きな素数を 10個 出力する ■ 1,000 より大きな素数を 10個 出力する 無限ループに陥る 最初の 10個だけが処理される require 'prime' require 'prime' infinity = 1.0/0 infinity = 1.0/0 (1000..infinity).select do |i| (1000..infinity).lazy.select do |i| i.prime? i.prime? end. # ここで、無限ループに陥る end.take(10). # 最初の10個だけを評価する take(10).each do |i| each do |i| puts i puts i end end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 4. Enumerable#lazy のベンリなところ 3 【Enumerable#lazy を使わなければ】 【Enumerable#lazy なら】 (1) map などの処理ごとに配列を生成する (1) map などの処理ごとに、 ・大量の配列生成をともなうので、 Enumerator::Lazy オブジェクトを生成 メモリ効率が悪い ・すべての要素を配列にしたりしない (2) 最終的に使われなくても、生成する ・大量のメモリを消費したりしない ・もったいない (2) 次に使う分だけ生成する ・下の例だと、10個目より後は不要 ・エコ (3) 無限ループに陥る ・下の例だと、10個目より後は何もしない ・無限個の要素を処理しようとするので (3) 無限を無限のまま扱える 無限ループになっちゃう。 ・宇宙ヤバい ■ 1,000 より大きな素数を 10個 ■ ".rb" ファイルを 10個 列挙 require 'prime' require 'find' infinity = 1.0/0 Find.find("/").lazy.select do |f| (1000..infinity).lazy.select do |i| File.file?(f) && f.end_with?(".rb") i.prime? end.take(10).each do |f| end.take(10). # 最初の10個だけを評価する puts f each do |i| end puts i end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 5. Enumeratable#lazy の内部動作(1) 4 Enumerable#lazy は Enumerator::Lazy オブジェクトを返す Enumerator::Lazy は Enumerator のサブクラス Enumerator : 外部イテレータを実現するためのクラス 内部では Fiber を使って実装されている Enumerator::Lazy は、Enumerable モジュールのメソッドを再定義 map 、select、take などのメソッドの返り値は、Enumerator::Lazy オブジェクト ※ Enumerable モジュールで増えるメソッドは Enumerable#lazy だけ。 ここで、Enumerator::Lazy オブジェクトを生成。 infinity = 1.0/0 (1000..infinity).lazy. 1個ずつ処理する。 select do |i| i.prime? select や take などの Enumerable モジュールのメソッド end. は、Enumerator::Lazy クラスでは take(10).each do |i| puts i 1個ずつ処理する Enumerator::Lazy オブジェクト end を返すように再定義されている。 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 6. Enumerable#lazy の内部動作(2) 5 Enumerable#lazy は最初の1個だけがんばって処理。残りは後回し。 2個目以降については、後工程で必要になって初めて、前工程の処理を行う。 inf = 1.0/0 (1000..inf).lazy.select do |i| 【lazy Fiber】 (1000..inf).lazy i.prime? 値を順に yield する Enumerable::Lazy オブジェクトを生成 end.take(10). # 最初の10個だけ評価 次の値を yield して、 lazy Fiber は中断する。 each do |i| puts i 【select Fiber】 select {|i| i.prime?} end 素数である場合だけ yield する E::Lazy オブジェクト 素数となる値が来るまで、親 Fiber に値を要求する。 素数があれば、その値を yield して select Fiber は中断 【take Fiber】 take(10) 最初の 10個であれば yield する E::Lazy オブジェクト 親 Fiber から得られた値を 10個目までは 子Fiber に そのまま yield し、take Fiber は処理を中断する。 【each Fiber】 each {|i| puts i } 親Fiber から受け取った値をそのまま 表示する。 ループごとに親 Fiber に次の値を要求する。 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 7. Enumerator の復習 6 Enumerator ■ Object#enum_for による Enumerator の生成 Enumerable なオブジェクト enum = "abc".enum_for(:each_byte) enum.each do |byte| を簡単に作れる puts byte ~Ruby 1.8.6 の標準添付ライブラリ end Ruby 1.8.7 の組込ライブラリ ■ Enumerator.new による Enumerator の生成 Enumerable::Enumerator Ruby 1.8.8~ の組込ライブラリ str = "abc" enum = Enumerator.new(str, :each_byte) Enumerator enum.each do |byte| Ruby 1.9 で Generator の機能を puts byte 取り込み強化される end ■ Ruby 1.8 の添付ライブラリ Generator ■ Enumerator.new (Ruby 1.9 feature ) g = Generator.new do |yielder| enum = Enumerator.new do |yielder| "abc".each_byte do |byte| "abc".each_byte do |byte| yielder.yield byte yielder << byte end end end end # callcc だから遅い # Fiber を使っているから速い g.each do |byte| enum.each do |byte| puts byte puts byte end end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 8. Enumerator と Fiber 7 Enumerator は Fiber を活用するデザインパターンの1つ Fiber における難しい概念を隠ぺい Fiber.yield => Enumerator::Yielder#<< 、 Enumerator#each による列挙 Enumerator を使いこなせれば、十分 Fiber のメリットを活用できる 《参考: Fiber にできて、Enumerator でできないこと》 親 Fiber から 子Fiber へのデータの送付(Fiber.yield の返り値の利用) ■ Enumerator の例(フィボナッチ数) ■ 《参考》 Fiberの例(フィボナッチ数) fib = Enumerator.new do |yielder| fib = Fiber.new do a = b = 1 a = b = 1 loop do loop do Fiber.yield a yielder << a a, b = b, a + b a, b = b, a + b end end end end def fib.each fib.each do |i| loop do これが必要。 Enumerator の break if i > 1000 内部実装まで yield fib.resume だけど、これが end puts i 考えなくていい end 難しい。(汗) end fib.each do |i| break if i > 1000 puts i end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 9. Enumerator はベンリ 8 Enumerator なら Enumerable の便利メソッドを使える。 ブロック付メソッド呼び出しは単純なイテレーションならいいけど。。。 Enumerator はオブジェクトなので、使い回しが簡単。 引数にしたり、返り値にしたり、インスタンス変数に格納したり Enumerator オブジェクトの生成も慣れれば簡単。 ■ Enumerator の例(フィボナッチ数) ■ 《参考》 ブロック付メソッド呼び出しの例 fib = Enumerator.new do |yielder| def fibonacci a = b = 1 a = b = 1 loop do loop do yielder << a 慣れれば、 yield a a, b = b, a + b カンタン a, b = b, a + b end end end end fib.each do |i| fibonacci do |i| break if i > 1000 break if i > 1000 puts i 単純なイテレーション end puts i ならいいけど・・・。 end fib.each_cons(2) do |i, j| Enumerable break if i > 1000 prev = nil の便利メソッド fibonacci do |i| puts "#{i} #{j}" を使い放題 end break if i > 1000 面倒 ! ! puts "#{prev} #{i}" if prev prev = i end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 10. (おまけ) Enumerator の利用例 データ構造に対する巡回方法を Enumerator で抽象化可能 1 2 3 1 4 7 マトリックスに対して、 行 => 列 の順で列挙するか 4 5 6 2 5 8 列 => 行 の順で列挙するか 7 8 9 3 6 9 / ① /bin /usr /etc /home ② ③ ④ ⑤ 木構造に対して、 /usr/local ⑥ /usr/lib ⑦ /home/cuzic ⑧ 幅優先探索を行うか 深さ優先探索を行うか / ① /bin /usr /etc /home ② ③ ⑥ ⑦ /usr/local /usr/lib /home/cuzic ④ ⑤ ⑧ 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 11. Enumerable#lazy の実装 10 Enumerable#lazy を使うと、Enumerable のメソッドの返り値が Enumerator::Lazy オブジェクトになる Enumerable モジュールに増やすメソッドは Enumerable#lazy だけ module Enumerable def select(&block) def lazy Lazy.new(self){|yielder, val| Enumerator::Lazy.new(self) if block.call(val) end yielder << val end end } class Enumerator end class Lazy < Enumerator def initialize(obj, &block) def take(n) super(){|yielder| taken = 0 begin Lazy.new(self){|yielder, val| obj.each{|x| if block if taken < n block.call(yielder, x) yielder << val else taken += 1 yielder << x else end raise StopIteration } end rescue StopIteration } end end } …… end end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 12. Enumerable#lazy の活用例 11 Enumerable#lazy を上手に活用すると生成、フィルタを順に 処理するプログラムをメソッドチェーンで簡潔に記述できる。 require 'forwardable' def map &block @lazy = @lazy.map &block class FizzBuzz self extend Forwardable end def_delegators :@lazy, :each def fizzbuzz map do |i| def self.each &blk (i % 15 == 0) ? "FizzBuzz" : i fb = self.new end fb.fizzbuzz.fizz.buzz. end take(30).each(&blk) def buzz end map do |i| (i % 5 == 0) ? "Buzz" : i def initialize end inf = 1.0/0 end @lazy = (1..inf).lazy def fizz end map do |i| (i % 3 == 0) ? "Fizz" : i def take n end @lazy = @lazy.take n end self end end FizzBuzz.each do |i| puts i end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 13. (おまけ)パイプライン処理 12 Enumerator を活用すると、UNIX のパイプのように処理を書ける 下記の例では本当にパイプ(|)で処理する例 ついカッとなってやった。今は反省している。 ふつうはメソッドチェーンで十分実用的 フィルタ処理をオブジェクトにしたいときはこういう方法もベンリかも。 Enumerator.new の書き方に精通していないと、分かりにくい。。。 Enumerable#map とか使って、書けたら分かりやすいのにな。。。 # Enumerable#lazy は無関係だけど。。。 class Pipeline <Enumerator attr_accessor :source def main def |(other) fb = FizzBuzz.new(15, "FizzBuzz") other.source = self buzz = FizzBuzz.new( 5, "Buzz") other fizz = FizzBuzz.new( 3, "Fizz") end end inf = 1.0/0 sink = Pipeline.new(1..inf) class FizzBuzz <Pipeline pipe = sink | fb | buzz | fizz def initialize n, subst pipe.take(30).each{|i| puts i} super() do |y| @source.each do |i| end y << (i % n == 0) ? subst : i end if $0 == __FILE__ end main end end end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 14. (おまけ) もっと lazy に 13 クロージャを活用すれば、もっと評価タイミングを遅延できる 値ではなく、クロージャを要素とし、必要なときクロージャを評価する クロージャなら、memoize も簡単に実装可能 同じ計算を2回以上しないようにできる。 # 下記の例も Enumerable#lazy と関係ない。。。 # memoize しない場合。同じ計算を何度もする。 # memoize版。同じ計算は1度だけ。圧倒的に速い。 # すごい遅い。 def add a, b memo = nil def add a, b lambda do lambda do return memo if memo return a.() + b.() memo = a.() + b.() end return memo end end end fib = Enumerator.new do |yielder| a = b = lambda{ 1 } fib = Enumerator.new do |yielder| loop do a = b = lambda{ 1 } yielder << a loop do a, b = b, add(a, b) yielder << a end a, b = b, add(a, b) end end end fib.take(36).each do |i| puts i.() fib.take(36).each do |i| end puts i.() end 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」
  • 15. まとめ 14 Enumerable#lazy @yhara さんの作品 無限を無限のまま扱える 次の1個だけ処理して、残りは後回し 全部一気に処理するより、必要なメモリ量が少なくて済む Enumerator Enumerator::Lazy の内部実装で大活躍 Enumerator は Fiber より分かりやすく、実用的。 Fiber でやりたいことの大部分は Enumerator で十分可能 発展的な使い方 メソッドチェーンでパイプライン処理とか クロージャを使ってより遅延評価させたり。 2012/11/10 Scala/Clojure/Ruby勉強会 「Enumerable#lazy について」