怠惰なRubyistへの道Enumerator::Lazyの使いかた      Chikanaga Tomoyuki         (@nagachika)          Yokohama.rb                      ...
AgendaEnumerableEnumeratorEnumerator::Lazy                   2
WARNING 今日の話は Ruby 2.0 の新機能について              3
Ruby 2.02013年リリース予定[ruby-dev:44691] よりAug. 24 2012: big-feature freezeOct. 24 2012: feature freezeFeb. 24 2013: 2.0 releas...
Ruby 2.0未来の話           5
2.0 is in   development       ※注※    仕様は開発中のものでありリリース版では変更される場合があります                      6
Install Ruby 2.0未来を手中にrvm, rbenv を使っていればrvm install ruby-headrbenv install 2.0-devel                          7
Ruby 2.0 for   Windows               8
Self Introductiontwitter id: @nagachikaruby trunk changes(http://d.hatena.ne.jp/nagachika)CRuby committerYokohama.rb → 福岡遠...
Enumerator::Lazy                   10
Enumerator::Lazy  の前に                   11
Enumerable             12
Enumerableもちろん使ってますよね?               13
Array, Hash, IO...Array や Hash, IO は    Enumerable を   include している                     14
Enumerable【形容詞】 数えられる            [日本語 WordNet(英和)) 可算;可付番       [クロスランゲージ 37分野専門語辞書]Capable of being enumerated;countable ...
Enumerable「each メソッドを呼ぶと、何かが順に(N回) yield で渡される」というルール(N >= 0)                      16
Enumerableeach メソッドが定義されているクラスに include して使う(Mix-in)                    17
Enumerableeach だけ用意しておけばmap, select, reject, grep, etc...といったメソッドが使えるようになる(これらのメソッドが each を使って実装されている)                    ...
An Exampleclass A  include Enumerable  def each    yield 0    yield 1    yield 2  endendA.new.map{|i| i * 2 } # => [ 0, 2,...
ここまでのまとめEnumerable は each メソッドを使って多彩なメソッドを追加するなにが「数え上げられる」のかはeach メソッドがどのようにyield を呼び出すかで決まる                             20
Enumerator使ってます?              21
Enumeratoreach に渡すブロックを保留した状態でオブジェクトとして持ち回す                    22
to_enum, enum_forEnumerator の作りかた•   Enumerator.new(obj, method=:each, *args)•   obj.to_enum(method=:each, *args)•   obj.e...
Object#enum_foreach 以外の任意のメソッドの呼び出しをEnumerator にできる(実は Enumerable でなくてもいい)e_byte = $stdin.enum_for(:each_byte)  => バイトごとに ...
Enumerator.new{|y|}e =   Enumerator.new{|y|  y   << 0  y   << :foo  y   << 2}ブロックが each の代わり。ブロックパラメータ y に << するとyield するこ...
Enumerator.new{|y|}class A  def each    yield 0    yield :bar    yield 2  endendA.new.to_enumと同じ                      26
Enumerator as External Iterator外部イテレータとして使えるe = (0..2).to_enume.next # => 0         each が yield する値がe.next # => 1        ...
Method Chainmap, select など一部のメソッドはブロックを省略すると Enumerator を返すので複数のメソッドを組み合わせて使うary.map.with_index { |v,i| ... }             ...
Method Chain[:a, :b, :c, :d].map.with_index do |sym, i|  i.even? ? sym : iend=> [:a, 1, :c, 3]         Enumerator         ...
with_index[ruby-dev:31953] Matz wrote...  mapがenumeratorを返すとobj.map.with_index{|x,i|....}ができるのが嬉しいので導入したのでした。というわけで、* each...
Secret Story of  Enumerator.  Enumerator はwith_index の為に    生まれた!  というのは嘘ですが 主な用途は with_index の ためのような気がします               ...
ここまでのまとめ• Enumerator• Object#to_enum, enum_for• 外部イテレータ化  • Method Chain•                             32
Enumerator::Lazy2.0 の新機能                   33
Enumerator::LazyEnumeratorのサブクラス                    34
Enumerable#lazyEnumerator::Lazy の作りかたEnumerable#lazy を呼ぶ>> (0..5).lazy=> #<Enumerator::Lazy: 0..5>                        ...
Enumerator::LazyLazyのmap,select,zipなど一部のメソッドがさらにLazyを返す>> (0..5).lazy.map{|i| i * 2}=> #<Enumerator::Lazy:#<Enumerator::La...
Enumerator::Lazy> Enumerator::Lazy.instance_methods(false)      map          collect                 flat_mapcollect_concat...
forceEnumrator::Lazy#forceto_a の alias遅延されているイテレータの評価を実行                        38
A Lazy Demo>> l = (0..5).lazy=> <Enumerator::Lazy: 0..5>>> l_map = l.map{|i| p i; i * 2 }=> <Enumerator::Lazy: #<Enumerato...
Enumeratorとの違いMethod Chain の使いかたがより強力に中間データの抑制                           40
Pitfall of   Enumerator (1)map, select のようにブロックの戻り値を利用するメソッドを複数繋げることができない(しても意味がなくなる)(0..5).map.select{|i| i % 2 == 0 } =>...
True Method Chainmap や select といったメソッドもいくつでもMethod Chain できる。そう、Lazy ならね。# 1 から 1000 のうち任意の桁に7を含む数を返す(1..1000).lazy.map(&:...
Pitfall of   Enumerator (2)map, select のようにブロックの戻り値を利用するメソッドを外部イテレータ化しても意味がないe = (0..5).selecte.next # => 0e.next # => 1e....
True External         Iteratormap などにブロックを渡せるので適用した結果を順に取り出せるl = (0..5).lazy.select{|i| i.even? }l.next # => 0l.next # => ...
Efficient Memory       UsageLazy は yield 毎に Method Chain の最後まで処理される                                 45
Enumerable versionlarge_array.map{...}.select{...}                                   46
Enumerable versionlarge_array.map{...}.select{...}      map                                   47
Enumerable versionlarge_array.map{...}.select{...}      map        select                                   48
Enumerable versionlarge_array.map{...}.select{...}        GCされる      map     select                                   49
Enumerable versionlarge_array.map{...}.select{...}        GCされる      map     select      map 結果のためlarge_array と同じくらいの     ...
Lazy versionlarge_array.lazy.map{...}.select{...}.force                                              51
Lazy versionlarge_array.lazy.map{...}.select{...}.force                                              52
Lazy versionlarge_array.lazy.map{...}.select{...}.force           GC ed                                              53
Lazy versionlarge_array.lazy.map{...}.select{...}.force                                              54
Lazy versionlarge_array.lazy.map{...}.select{...}.force           GC ed                                              55
Lazy versionlarge_array.lazy.map{...}.select{...}.force                                              56
Lazy versionlarge_array.lazy.map{...}.select{...}.force       中間データが不要                                              57
Lazy Chain Demo>> (0..4).lazy.select{|i|   p “select:#{i}”; i.event? }.map{|i| p “map:#{i}”; i * 2 }.force“select:0”“map:0...
Lazy with IO例) $stdin から空行を読むまでの各行の文字数の配列を返す$stdin.lazy.take_while{|l|  ! l.chomp.empty?}.map {|l| l.chomp.size }         ...
Lazy with IOEnumerable だと空行まで先に読んでしまう。Lazy なら1行読むたびに take_while/map のブロックが実行される → 逐次処理できる                                 ...
Lazy List無限に続く要素を扱えるlist = (0..Float::INFINITY)list.map{|i| i * 2}.take(5) => 返ってこないlist.lazy.map{|i| i * 2 }.take(5).forc...
Pitfall of Lazy?メモ化されない(force を2回呼ぶともう一度 each が呼ばれる) IOなど副作用のある each だと結果が 変化するけどいいのかなぁ(いいかも)enum_for のように each のかわりになるメソッ...
Lazy as a Better   Enumerator     Lazy は  Enumerator の    正統進化版                   63
Happy LazyProgramming!               64
One More Thing!https://github.com/nagachika/lazy_sample                                           65
Upcoming SlideShare
Loading in …5
×

怠惰なRubyistへの道

2,474
-1

Published on

みなとRuby会議01での発表資料の配布版

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,474
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

怠惰なRubyistへの道

  1. 1. 怠惰なRubyistへの道Enumerator::Lazyの使いかた Chikanaga Tomoyuki (@nagachika) Yokohama.rb 1
  2. 2. AgendaEnumerableEnumeratorEnumerator::Lazy 2
  3. 3. WARNING 今日の話は Ruby 2.0 の新機能について 3
  4. 4. Ruby 2.02013年リリース予定[ruby-dev:44691] よりAug. 24 2012: big-feature freezeOct. 24 2012: feature freezeFeb. 24 2013: 2.0 releaseRuby の生誕 20 周年 4
  5. 5. Ruby 2.0未来の話 5
  6. 6. 2.0 is in development ※注※ 仕様は開発中のものでありリリース版では変更される場合があります 6
  7. 7. Install Ruby 2.0未来を手中にrvm, rbenv を使っていればrvm install ruby-headrbenv install 2.0-devel 7
  8. 8. Ruby 2.0 for Windows 8
  9. 9. Self Introductiontwitter id: @nagachikaruby trunk changes(http://d.hatena.ne.jp/nagachika)CRuby committerYokohama.rb → 福岡遠征中Sound.rb(ruby-coreaudio, ruby-puredata) 9
  10. 10. Enumerator::Lazy 10
  11. 11. Enumerator::Lazy の前に 11
  12. 12. Enumerable 12
  13. 13. Enumerableもちろん使ってますよね? 13
  14. 14. Array, Hash, IO...Array や Hash, IO は Enumerable を include している 14
  15. 15. Enumerable【形容詞】 数えられる [日本語 WordNet(英和)) 可算;可付番 [クロスランゲージ 37分野専門語辞書]Capable of being enumerated;countable [Wikitionary] 15
  16. 16. Enumerable「each メソッドを呼ぶと、何かが順に(N回) yield で渡される」というルール(N >= 0) 16
  17. 17. Enumerableeach メソッドが定義されているクラスに include して使う(Mix-in) 17
  18. 18. Enumerableeach だけ用意しておけばmap, select, reject, grep, etc...といったメソッドが使えるようになる(これらのメソッドが each を使って実装されている) 18
  19. 19. An Exampleclass A include Enumerable def each yield 0 yield 1 yield 2 endendA.new.map{|i| i * 2 } # => [ 0, 2, 4 ] 19
  20. 20. ここまでのまとめEnumerable は each メソッドを使って多彩なメソッドを追加するなにが「数え上げられる」のかはeach メソッドがどのようにyield を呼び出すかで決まる 20
  21. 21. Enumerator使ってます? 21
  22. 22. Enumeratoreach に渡すブロックを保留した状態でオブジェクトとして持ち回す 22
  23. 23. to_enum, enum_forEnumerator の作りかた• Enumerator.new(obj, method=:each, *args)• obj.to_enum(method=:each, *args)• obj.enum_for(method=:each, *args)• Enumerator.new{|y| ...} ↑これだけちょっと特殊 23
  24. 24. Object#enum_foreach 以外の任意のメソッドの呼び出しをEnumerator にできる(実は Enumerable でなくてもいい)e_byte = $stdin.enum_for(:each_byte) => バイトごとに yielde_line = $stdin.enum_for(:each_line) => 行ごとに yield 24
  25. 25. Enumerator.new{|y|}e = Enumerator.new{|y| y << 0 y << :foo y << 2}ブロックが each の代わり。ブロックパラメータ y に << するとyield することになる。 25
  26. 26. Enumerator.new{|y|}class A def each yield 0 yield :bar yield 2 endendA.new.to_enumと同じ 26
  27. 27. Enumerator as External Iterator外部イテレータとして使えるe = (0..2).to_enume.next # => 0 each が yield する値がe.next # => 1 順に next で取り出せるe.next # => 2e.next=> StopIteration: iteration reached an end 27
  28. 28. Method Chainmap, select など一部のメソッドはブロックを省略すると Enumerator を返すので複数のメソッドを組み合わせて使うary.map.with_index { |v,i| ... } 28
  29. 29. Method Chain[:a, :b, :c, :d].map.with_index do |sym, i| i.even? ? sym : iend=> [:a, 1, :c, 3] Enumerator 独自のメソッド 29
  30. 30. with_index[ruby-dev:31953] Matz wrote... mapがenumeratorを返すとobj.map.with_index{|x,i|....}ができるのが嬉しいので導入したのでした。というわけで、* eachにもmapにもwith_indexが付けられて嬉しいというのが本当の理由です。 30
  31. 31. Secret Story of Enumerator. Enumerator はwith_index の為に 生まれた! というのは嘘ですが 主な用途は with_index の ためのような気がします 31
  32. 32. ここまでのまとめ• Enumerator• Object#to_enum, enum_for• 外部イテレータ化 • Method Chain• 32
  33. 33. Enumerator::Lazy2.0 の新機能 33
  34. 34. Enumerator::LazyEnumeratorのサブクラス 34
  35. 35. Enumerable#lazyEnumerator::Lazy の作りかたEnumerable#lazy を呼ぶ>> (0..5).lazy=> #<Enumerator::Lazy: 0..5> 35
  36. 36. Enumerator::LazyLazyのmap,select,zipなど一部のメソッドがさらにLazyを返す>> (0..5).lazy.map{|i| i * 2}=> #<Enumerator::Lazy:#<Enumerator::Lazy: 0..5>:map> 36
  37. 37. Enumerator::Lazy> Enumerator::Lazy.instance_methods(false) map collect flat_mapcollect_concat select find_all reject grep zip take take_while drop drop_wihle cycle lazy force [ruby 2.0.0dev (2012-05-30 trunk 35844)] 37
  38. 38. forceEnumrator::Lazy#forceto_a の alias遅延されているイテレータの評価を実行 38
  39. 39. A Lazy Demo>> l = (0..5).lazy=> <Enumerator::Lazy: 0..5>>> l_map = l.map{|i| p i; i * 2 }=> <Enumerator::Lazy: #<Enumerator::Lazy: 0..5>:map># この時点ではまだブロックの内容は実行されていない!>> l_map.force012345=> [0, 2, 4, 6, 8, 10]# force を呼ぶと実行される 39
  40. 40. Enumeratorとの違いMethod Chain の使いかたがより強力に中間データの抑制 40
  41. 41. Pitfall of Enumerator (1)map, select のようにブロックの戻り値を利用するメソッドを複数繋げることができない(しても意味がなくなる)(0..5).map.select{|i| i % 2 == 0 } => [ 0, 2, 4 ]↑ map の意味がなくなっている 41
  42. 42. True Method Chainmap や select といったメソッドもいくつでもMethod Chain できる。そう、Lazy ならね。# 1 から 1000 のうち任意の桁に7を含む数を返す(1..1000).lazy.map(&:to_s).select{|s| /7/ =~ s}.force 42
  43. 43. Pitfall of Enumerator (2)map, select のようにブロックの戻り値を利用するメソッドを外部イテレータ化しても意味がないe = (0..5).selecte.next # => 0e.next # => 1e.next # => 2e.next # => 3↑ select の意味がなくなっている 43
  44. 44. True External Iteratormap などにブロックを渡せるので適用した結果を順に取り出せるl = (0..5).lazy.select{|i| i.even? }l.next # => 0l.next # => 2l.next # => 4l.next # => StopIteration: iteration reached an end 44
  45. 45. Efficient Memory UsageLazy は yield 毎に Method Chain の最後まで処理される 45
  46. 46. Enumerable versionlarge_array.map{...}.select{...} 46
  47. 47. Enumerable versionlarge_array.map{...}.select{...} map 47
  48. 48. Enumerable versionlarge_array.map{...}.select{...} map select 48
  49. 49. Enumerable versionlarge_array.map{...}.select{...} GCされる map select 49
  50. 50. Enumerable versionlarge_array.map{...}.select{...} GCされる map select map 結果のためlarge_array と同じくらいの 中間データが必要 50
  51. 51. Lazy versionlarge_array.lazy.map{...}.select{...}.force 51
  52. 52. Lazy versionlarge_array.lazy.map{...}.select{...}.force 52
  53. 53. Lazy versionlarge_array.lazy.map{...}.select{...}.force GC ed 53
  54. 54. Lazy versionlarge_array.lazy.map{...}.select{...}.force 54
  55. 55. Lazy versionlarge_array.lazy.map{...}.select{...}.force GC ed 55
  56. 56. Lazy versionlarge_array.lazy.map{...}.select{...}.force 56
  57. 57. Lazy versionlarge_array.lazy.map{...}.select{...}.force 中間データが不要 57
  58. 58. Lazy Chain Demo>> (0..4).lazy.select{|i| p “select:#{i}”; i.event? }.map{|i| p “map:#{i}”; i * 2 }.force“select:0”“map:0”“select:1”“select:2”“map:2”“select:3”“select:4”“map:4”=> [0, 4, 8] 58
  59. 59. Lazy with IO例) $stdin から空行を読むまでの各行の文字数の配列を返す$stdin.lazy.take_while{|l| ! l.chomp.empty?}.map {|l| l.chomp.size } 59
  60. 60. Lazy with IOEnumerable だと空行まで先に読んでしまう。Lazy なら1行読むたびに take_while/map のブロックが実行される → 逐次処理できる 60
  61. 61. Lazy List無限に続く要素を扱えるlist = (0..Float::INFINITY)list.map{|i| i * 2}.take(5) => 返ってこないlist.lazy.map{|i| i * 2 }.take(5).force => [0, 2, 4, 6, 8] 61
  62. 62. Pitfall of Lazy?メモ化されない(force を2回呼ぶともう一度 each が呼ばれる) IOなど副作用のある each だと結果が 変化するけどいいのかなぁ(いいかも)enum_for のように each のかわりになるメソッドを指定できない 62
  63. 63. Lazy as a Better Enumerator Lazy は Enumerator の 正統進化版 63
  64. 64. Happy LazyProgramming! 64
  65. 65. One More Thing!https://github.com/nagachika/lazy_sample 65

×