Enumerable な何か、
あるいは怠惰なる反復


            2012.08.11 るりま読書会
    SAWADA Tadashi a.k.a. @cesare
こんにちは
沢田正
@cesare
Startup な会社の
     中の人
Tokyu.rb
発音にうるさい人
ところで
Enumerable
いなめらぶる
いにゅーめらぶる
閑話休題
今日のお品書き
•Enumerable なクラス

• 自作 Enumerable

• Enumerable#lazy
each が dis られた
直後に、each重要
という話をします
Enumerable な
   クラス
•Array

• Hash

• ...
探してみよう
下調べ
Class.constants
# => [:Object, :Module,
      :Class, :BasicObject, ...]
Class.const_get(:String)
# => String
"string".is_a?(String)
# => true
String.ancestors
# => [String,テキスト
              Comparable,
      Object, Kernel,
      BasicObject]
•コレクションの変換
•コレクションの取捨選択
• Enumerable な機能を活用
Class.constants
 .map {|name| Class.const_get(name) }
 .select {|obj| obj.is_a?(Class) }
 .map {|clazz| clazz.ancestors }
 .select {|classes|
     classes.member?(Enumerable) }
 .map(&:first)
[Array, Hash, Struct, Range,
 IO, File, Dir, Enumerator,
 StringIO]
Array, Hash,
   Range
Struct
IO, File, Dir,
  StringIO
•1行ずつ処理

• 1バイトずつ処理

• 1エントリーずつ処理
Enumerator も
 Enumerable
Enumerator
 ってなに?
外部イテレーター
e = [1,2,3].each
# => #<Enumerator: ...>
# e = [1,2,3].each

e.next
# => 1
# e = [1,2,3].each

e.next
e.next
# => 2
# e = [1,2,3].each

e.next
e.next
e.next
# => 3
# e = [1,2,3].each

e.next
e.next
e.next
e.next
# => StopIteration:
   iteration reached an end
# e = [1,2,3].each

e.next
e.next
e.next
e.rewind
e.next
# => 1
Enumerator も
 Enumerable
e = [1,2,3].each
# => #<Enumerator: ...>

e.map{|i| i.to_s }
# => ["1", "2", "3"]
ここまでのまとめ
Enumerable なクラスとは、



•コレクション的なやつ
• IO的なやつ

•Enumerator
Enumerable ク
  ラスを作る
自作のデータ構造を
Enumerable 化
   したい
やりかた
•each を実装

• include Enumerable
ポイント
• コレクションを回す each は自分で頑張る
• ブロックを渡されない場合の each は
 Enumerator を返す


• 他のメソッドは Enumerable にお任せ
実装例
1 class Directory
 2   include Enumerable
 3
 4   def initialize(dirname)
 5     @dirname = dirname
 6     @files = Dir.open(dirname) {|dir|
 7       dir.reject {|name| name == "." || name == ".." }
 8     }
 9   end
10
11   def each(&block)
12     if block_given?
13       @files.each do |name|
14          path = File.join(@dirname, name)
15          if File.directory?(path)
16            Directory.new(path).each(&block)
17          else
18            yield path
19          end
20       end
21     else
22       Enumerator.new(self, :each)
23     end
24
      gist.github.com/3296137
     end
25 end
1 class Directory
 2   include Enumerable
 3
 4   def initialize(dirname)
 5     @dirname = dirname
 6     @files = Dir.open(dirname) {|dir|
 7       dir.reject {|name| name == "." || name == ".." }
 8     }
 9   end
10
11   def each(&block)
12     if block_given?
13       @files.each do |name|
14          path = File.join(@dirname, name)
15          if File.directory?(path)
16            Directory.new(path).each(&block)
17          else
18            yield path
19          end
20       end
21     else
22       Enumerator.new(self, :each)
23     end
24   end
25 end
ここまでのまとめ
Enumerable にするには、



•each が Enumerable の要

•each 書かないと負け><
問題点
Directory.new("~/git").map{|f| f }
# => しばらく返ってこない・・・
Directory.new("/").map{|f| f }
# => メモリ足りなくて死ぬ><
そこで
Enumerable#lazy
    ですよ
遅延評価版
Enumerable
•gem install enumerable-lazy
•Ruby 2.0 なら標準装備
[1,2,3].lazy
# => #<Enumerator::Lazy: ...>
[1,2,3].lazy.each
# => #<Enumerator::Lazy: ...>
[1,2,3].lazy.map{|i| i.to_s }
# => #<Enumerator::Lazy: ...>
[1,2,3].lazy.map{|i| i.to_s }.first
# => ["1"]
[1,2,3].lazy.map{|i| i.to_s }.to_a
# => ["1", "2", "3"]
自作 Enumerable
    は?
Directory.new("~/git")
  .lazy.map{|f| f }
# => #<Enumerator::Lazy: ...>
Directory.new("~/git")
  .lazy
  .grep(/.rb$/)
  .take(100)
Directory.new("~/git")
 .lazy
 .grep(/.hs$/)
 .each{|f| zmq.send(f ) }
つかいどころ
•巨大なデータ

• 終わらないデータ

• ストリーミングとか
まとめ
•Enumerable なのは
 コレクションとか IO とか

•each 超重要><

•遅延評価すごいよ遅延評価
questions.take(n).map do |q|
 q.answer
end
ご清聴ありがとう
 ございました

Enumerable な何か、あるいは怠惰なる反復

Editor's Notes

  • #2 \n
  • #3 \n
  • #4 \n
  • #5 \n
  • #6 \n
  • #7 \n
  • #8 \n
  • #9 \n
  • #10 \n
  • #11 \n
  • #12 \n
  • #13 \n
  • #14 \n
  • #15 \n
  • #16 \n
  • #17 \n
  • #18 \n
  • #19 &amp;#x3044;&amp;#x308D;&amp;#x3093;&amp;#x306A;&amp;#x3084;&amp;#x308A;&amp;#x65B9;&amp;#x304C;&amp;#x3042;&amp;#x308B;&amp;#x306F;&amp;#x305A;&amp;#x3002;\n&amp;#x3053;&amp;#x3053;&amp;#x3067;&amp;#x306F;&amp;#x4E00;&amp;#x4F8B;&amp;#x3092;&amp;#x3002;\n
  • #20 &amp;#x30ED;&amp;#x30FC;&amp;#x30C9;&amp;#x3055;&amp;#x308C;&amp;#x3066;&amp;#x3044;&amp;#x308B;&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x306E;&amp;#x30EA;&amp;#x30B9;&amp;#x30C8;&amp;#x304C;&amp;#x307B;&amp;#x3057;&amp;#x3044;&amp;#x3002;\n&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x306F;&amp;#x5B9A;&amp;#x6570;&amp;#x3067;&amp;#x3082;&amp;#x3042;&amp;#x308B;&amp;#x304B;&amp;#x3089;&amp;#x3001;&amp;#x305D;&amp;#x3053;&amp;#x304B;&amp;#x3089;&amp;#x63A2;&amp;#x3057;&amp;#x3066;&amp;#x307F;&amp;#x308B;&amp;#x3002;\n\n
  • #21 &amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x540D;&amp;#x304B;&amp;#x3089;&amp;#x3001;&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x306E;&amp;#x5B9F;&amp;#x4F53;&amp;#x3092;&amp;#x53D6;&amp;#x308A;&amp;#x51FA;&amp;#x3059;&amp;#x65B9;&amp;#x6CD5;\n
  • #22 &amp;#x30A4;&amp;#x30F3;&amp;#x30B9;&amp;#x30BF;&amp;#x30F3;&amp;#x30B9;&amp;#x304C;&amp;#x3001;&amp;#x3042;&amp;#x308B;&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;/&amp;#x30E2;&amp;#x30B8;&amp;#x30E5;&amp;#x30FC;&amp;#x30EB;&amp;#x306B;&amp;#x5C5E;&amp;#x3057;&amp;#x3066;&amp;#x3044;&amp;#x308B;&amp;#x304B;&amp;#x3069;&amp;#x3046;&amp;#x304B;&amp;#x3092;&amp;#x8ABF;&amp;#x3079;&amp;#x308B;\n
  • #23 &amp;#x3042;&amp;#x308B;&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x306E;&amp;#x7D99;&amp;#x627F;&amp;#x30C4;&amp;#x30EA;&amp;#x30FC;&amp;#x3092;&amp;#x8ABF;&amp;#x3079;&amp;#x308B;&amp;#x3002;\n&amp;#x5148;&amp;#x982D;&amp;#x306E;&amp;#x8981;&amp;#x7D20;&amp;#x304C;&amp;#x3001;&amp;#x8A72;&amp;#x5F53;&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x81EA;&amp;#x8EAB;&amp;#x3067;&amp;#x3042;&amp;#x308B;&amp;#x70B9;&amp;#x306B;&amp;#x6CE8;&amp;#x76EE;&amp;#x3002;\n
  • #24 \n
  • #25 &amp;#x3053;&amp;#x3053;&amp;#x3067;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x306B;&amp;#x5207;&amp;#x308A;&amp;#x66FF;&amp;#x3048;&amp;#x3066;&amp;#x30C7;&amp;#x30E2;&amp;#x3002;\n
  • #26 \n
  • #27 \n
  • #28 &amp;#x2192;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x3067;&amp;#x30C7;&amp;#x30E2; \nUser = Struct.new(:id, :name, :email)\n&amp;#x3068;&amp;#x304B;&amp;#x3067;&amp;#x4F8B;&amp;#x3092;&amp;#x898B;&amp;#x305B;&amp;#x308B;\n
  • #29 &amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x3067;&amp;#x30C7;&amp;#x30E2;\nFile, Dir &amp;#x3067;&amp;#x4F8B;&amp;#x3092;&amp;#x898B;&amp;#x305B;&amp;#x308B;\n
  • #30 Enumerable &amp;#x306A;&amp;#x30AF;&amp;#x30E9;&amp;#x30B9;&amp;#x306E;&amp;#x7279;&amp;#x5FB4;\n&amp;#x30B3;&amp;#x30EC;&amp;#x30AF;&amp;#x30B7;&amp;#x30E7;&amp;#x30F3;&amp;#x3068;&amp;#x306F;&amp;#x9650;&amp;#x3089;&amp;#x306A;&amp;#x3044;\n
  • #31 \n
  • #32 \n
  • #33 \n
  • #34 each &amp;#x306B;&amp;#x30D6;&amp;#x30ED;&amp;#x30C3;&amp;#x30AF;&amp;#x3092;&amp;#x6E21;&amp;#x3055;&amp;#x306A;&amp;#x3044;&amp;#x3068;&amp;#x3053;&amp;#x308D;&amp;#x306B;&amp;#x6CE8;&amp;#x76EE;\n(&amp;#x6B21;&amp;#x4EE5;&amp;#x964D;&amp;#x306B;&amp;#x4F8B;&amp;#x304C;&amp;#x7D9A;&amp;#x304F;&amp;#x3002;&amp;#x307E;&amp;#x3060;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x306B;&amp;#x5207;&amp;#x308A;&amp;#x66FF;&amp;#x3048;&amp;#x306A;&amp;#x3044;)\n
  • #35 \n
  • #36 \n
  • #37 \n
  • #38 \n
  • #39 &amp;#x5DFB;&amp;#x623B;&amp;#x3057;&amp;#x3082;&amp;#x3067;&amp;#x304D;&amp;#x308B;\n&amp;#x3053;&amp;#x3053;&amp;#x3067;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x306B;&amp;#x5207;&amp;#x66FF;&amp;#x3048;&amp;#x3066;&amp;#x30C7;&amp;#x30E2;\n
  • #40 \n
  • #41 Enumerator &amp;#x306B;&amp;#x5BFE;&amp;#x3057;&amp;#x3066; #map &amp;#x3092;&amp;#x547C;&amp;#x51FA;&amp;#x3059;\n&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x306B;&amp;#x5207;&amp;#x66FF;&amp;#x3048;&amp;#x3066;&amp;#x30C7;&amp;#x30E2;\n
  • #42 \n
  • #43 \n
  • #44 \n
  • #45 Array &amp;#x3068; Hash &amp;#x3058;&amp;#x3083;&amp;#x8DB3;&amp;#x308A;&amp;#x306A;&amp;#x3044;&amp;#x3053;&amp;#x3068;&amp;#x3001;&amp;#x3042;&amp;#x308B;&amp;#x3088;&amp;#x306D;&amp;#xFF1F;\n&amp;#x30C4;&amp;#x30EA;&amp;#x30FC;&amp;#x4F5C;&amp;#x308B;&amp;#x3068;&amp;#x304B;&amp;#x3002;\n
  • #46 &amp;#x624B;&amp;#x9593;&amp;#x304C;&amp;#x304B;&amp;#x304B;&amp;#x308A;&amp;#x305D;&amp;#x3046;&amp;#x306A;&amp;#x4E88;&amp;#x611F;&amp;#x3002;\n&amp;#x3067;&amp;#x3082;&amp;#x3001;&amp;#x3084;&amp;#x3063;&amp;#x3066;&amp;#x307F;&amp;#x305F;&amp;#x3089;&amp;#x610F;&amp;#x5916;&amp;#x3068;&amp;#x30B7;&amp;#x30F3;&amp;#x30D7;&amp;#x30EB;&amp;#x3002;\n
  • #47 Enumerable &amp;#x306B;&amp;#x306F; #each &amp;#x306F;&amp;#x5B58;&amp;#x5728;&amp;#x3057;&amp;#x306A;&amp;#x3044;&amp;#x3002;\n(&amp;#x3088;&amp;#x304F;&amp;#x8003;&amp;#x3048;&amp;#x3066;&amp;#x307F;&amp;#x308B;&amp;#x3068;&amp;#x5F53;&amp;#x7136;&amp;#x3002;&amp;#x5185;&amp;#x90E8;&amp;#x306E;&amp;#x30C7;&amp;#x30FC;&amp;#x30BF;&amp;#x69CB;&amp;#x9020;&amp;#x3092;&amp;#x77E5;&amp;#x3089;&amp;#x306A;&amp;#x3044;&amp;#x3068; each &amp;#x306F;&amp;#x66F8;&amp;#x3051;&amp;#x306A;&amp;#x3044;)\n
  • #48 \n
  • #49 &amp;#x5834;&amp;#x5408;&amp;#x306B;&amp;#x3088;&amp;#x3063;&amp;#x3066;&amp;#x306F;&amp;#x6CE5;&amp;#x81ED;&amp;#x3044;&amp;#x51E6;&amp;#x7406;&amp;#x3092;&amp;#x66F8;&amp;#x304B;&amp;#x306A;&amp;#x304D;&amp;#x3083;&amp;#x3044;&amp;#x3051;&amp;#x306A;&amp;#x3044;&amp;#x304B;&amp;#x3082;&amp;#x3002;\n
  • #50 \n
  • #51 \n
  • #52 &amp;#x30B3;&amp;#x30FC;&amp;#x30C9;&amp;#x3092;&amp;#x773A;&amp;#x3081;&amp;#x306A;&amp;#x304C;&amp;#x3089;&amp;#x89E3;&amp;#x8AAC;\n&amp;#x305D;&amp;#x306E;&amp;#x5F8C;&amp;#x3001;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x306B;&amp;#x5207;&amp;#x66FF;&amp;#x3048;&amp;#x3066;&amp;#x3001;&amp;#x5B9F;&amp;#x969B;&amp;#x306E;&amp;#x52D5;&amp;#x304D;&amp;#x3092;&amp;#x30C7;&amp;#x30E2;&amp;#x3002;\n
  • #53 \n
  • #54 \n
  • #55 &amp;#x6B21;&amp;#x306E;&amp;#x8A71;&amp;#x984C;&amp;#x3078;&amp;#x3002;\n
  • #56 git &amp;#x914D;&amp;#x4E0B;&amp;#x306B;&amp;#x306F;&amp;#x30D5;&amp;#x30A1;&amp;#x30A4;&amp;#x30EB;&amp;#x304C;&amp;#x3044;&amp;#x3063;&amp;#x3071;&amp;#x3044;&amp;#x3002;\nmap &amp;#x306E;&amp;#x5F8C;&amp;#x308D;&amp;#x306B;&amp;#x306F;&amp;#x307E;&amp;#x3060;&amp;#x307E;&amp;#x3060;&amp;#x51E6;&amp;#x7406;&amp;#x304C;&amp;#x7D9A;&amp;#x304F;&amp;#x3068;&amp;#x601D;&amp;#x3063;&amp;#x3066;&amp;#x304F;&amp;#x3060;&amp;#x3055;&amp;#x3044;&amp;#x3002;\n
  • #57 \n
  • #58 \n
  • #59 &amp;#x540D;&amp;#x524D;&amp;#x306E;&amp;#x901A;&amp;#x308A;&amp;#x3002;\n
  • #60 \n
  • #61 \n
  • #62 \n
  • #63 \n
  • #64 &amp;#x305F;&amp;#x3068;&amp;#x3048;&amp;#x3070;&amp;#x6700;&amp;#x521D;&amp;#x306E;&amp;#x8981;&amp;#x7D20;&amp;#x3092;&amp;#x898B;&amp;#x3088;&amp;#x3046;&amp;#x3068;&amp;#x3059;&amp;#x308B;&amp;#x3068;&amp;#x8A55;&amp;#x4FA1;&amp;#x304C;&amp;#x8D70;&amp;#x308B;&amp;#x3002;\n&amp;#x4F46;&amp;#x3057;&amp;#x3001;2,3 &amp;#x306B;&amp;#x3064;&amp;#x3044;&amp;#x3066;&amp;#x306F; map &amp;#x3055;&amp;#x308C;&amp;#x306A;&amp;#x3044;&amp;#x3002;\n&amp;#x2192;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x3067;&amp;#x30C7;&amp;#x30E2;\n
  • #65 \n
  • #66 lazy &amp;#x5BFE;&amp;#x5FDC;&amp;#x3057;&amp;#x3066;&amp;#x3084;&amp;#x3089;&amp;#x306A;&amp;#x304D;&amp;#x3083;&amp;#x30C0;&amp;#x30E1;&amp;#xFF1F;\n
  • #67 &amp;#x5B9F;&amp;#x88C5;&amp;#x5074;&amp;#x306B;&amp;#x306F;&amp;#x4F55;&amp;#x3082;&amp;#x5BFE;&amp;#x5FDC;&amp;#x3044;&amp;#x3089;&amp;#x306A;&amp;#x3044;&amp;#x3002;&amp;#x547C;&amp;#x51FA;&amp;#x3057;&amp;#x5074;&amp;#x3067;&amp;#x5358;&amp;#x306B; #lazy &amp;#x3092;&amp;#x6700;&amp;#x521D;&amp;#x306B;&amp;#x5165;&amp;#x308C;&amp;#x308B;&amp;#x3060;&amp;#x3051;&amp;#x3002;\n&amp;#x2192;&amp;#x30BF;&amp;#x30FC;&amp;#x30DF;&amp;#x30CA;&amp;#x30EB;&amp;#x306B;&amp;#x79FB;&amp;#x52D5;&amp;#x3057;&amp;#x3066;&amp;#x30C7;&amp;#x30E2;\n
  • #68 \n
  • #69 \n
  • #70 \n
  • #71 \n
  • #72 \n
  • #73 \n
  • #74 \n
  • #75 \n