Evolution Of Enumerator

Evolution Of Enumerator

74f896b312b786ee75a18073941e2457?s=128

Akinori MUSHA

March 23, 2019
Tweet

Transcript

  1. Evolution Of Enumerator Akinori Musha (@knu) Machimachi Inc. 2019-03-23 Rails

    Developer Meetup 2019
  2. ࣗݾ঺հ

  3. ෢ऀ থل (@knu) • GitHub: https://github.com/knu • Twitter: https://twitter.com/knu •

    Docker Hub !
  4. ෢ऀ থل (@knu) • ෢ऀ (Musha) • Kanji: martial/brave-one •

    Meaning: samurai • থل (Akinori) • Kanji: shine/bright-age/century • Meaning: (My parents' hope) Shine in the next (21st) century • knu • Meaning: ?
  5. ෢ऀ থل (@knu) • FreeBSD committer (Ports): knu@FreeBSD.org • Ruby

    committer: knu@ruby-lang.org • (Sorted)Setͷ࡞ऀ • Enumeratorͷ࡞ऀ • Rails: 4.1ʙ (2014) • Team Nokogiri, Team Huginn, … • A Father Of Two !" • Working at Machimachi Inc.
  6. झຯ • কع 㽪 !" ΞϚޒஈ (ࢦ͢ɺ؍Δ) • Minecraft ⛏$

    • ϥϯν % (ौ୩ɺத໨ࠇɺֶܳେֶɺࣗ༝ٰ͕͋ͨΓ) • ΫϥϑτϏʔϧΛҿΉ: Craft beer • ԻָΛௌ͘ ' (Progressive, metal music)
  7. None
  8. ϚνϚν͸ʮͻΒ͔Εͨɺͭͳ͕Γͷ͋ Δ஍ҬࣾձΛͭ͘Δʯͱ͍͏ϛογϣϯ Λܝ͛ɺ஍Ҭͷ՝୊Λղܾ͢ΔͨΊͷࣾ ձΠϯϑϥΛ࡞ΔҰ؀ͱͯ͠ɺۙ͝ॴ SNSͱ஍Ҭ৘ใϙʔλϧαΠτΛӡӦ͠ ͍ͯ·͢ɻ https://machimachi.com/ ۙ͝ॴ͞Μͱɺ·ͪͷࢠҭͯ΍Φεεϝ ͷ͓ళɾපӃͳͲʹ͍ͭͯ৘ใަ׵͕Ͱ ͖ΔαʔϏεͰ͢ɻ1

    1 ͣͬͱ੍໊࣮Ͱ͕ͨ͠ɺ࠷ۙχοΫωʔϜͰؾܰʹࢀՃͰ͖ΔΑ͏ʹͳΓ·͠ ͨɻ
  9. ϚνϚνΛࢧ͑Δٕज़ • Ruby / Rails • React.js • PostgreSQL /

    PostGIS • GCP / GAE Flex Environment ٕज़ϒϩάΛॻ͍͍ͯ·͢ʂ https://tech.machimachi.com/ We are hiring!
  10. EnumerableϞδϡʔϧͷྑ͞ • ϝιουʹண໨ͨ͠ػೳ֦ுʢmix-inʣ • ஋Λྻڍ͢ΔeachϝιουΛprimitiveͱͯ͠༻͍ɺmap, select, to_aͳͲΛఆٛ͢Δ • each͑͞ఆٛͯ͠include Enumerable͢Ε͹ɺ੝Γͩ͘

    ͞Μͷػೳ͕෇Ճ͞ΕΔ • ͲΜͳίϨΫγϣϯ΋ಉ͡࢖͍উखͰ࢖͑Δ
  11. ಺෦ΠςϨʔλͱ ֎෦ΠςϨʔλ

  12. ֎෦ΠςϨʔλ (External Iterator) • ଟ͘ͷݴޠɾϥΠϒϥϦ͸ͪ͜Β͕جຊ • ܁Γฦ͠Λ੍ޚ͢Δ໾ׂ͕ίϨΫγϣϯΦϒδΣΫτ·ͨ͸ϝιουͷ֎෦ɺ ͭ·Γ࢖͏ଆʹ͋Δ • ࢖͏ଆ͕ࣗ༝ͳλΠϛϯάͰΧʔιϧΛਐΊΒΕΔͷͰɺॲཧͷࣗ༝౓͸ߴ͍

    • ίϨΫγϣϯΛ࢖͏ଆ͕ϧʔϓม਺Λ؅ཧ͢Δඞཁ͕͋Δ఺͸໘౗ • forจͳͲͷ౶ҥߏจͰࢧԉ͢Δͷ͕௨ྫ • eachʹ͋ͨΔॲཧ͸forจɺmapʹ͋ͨΔॲཧ͸Ϧετ಺แදهɺͷΑ͏ʹಉ͡ ܁Γฦ͠Ͱ΋ߏจͷ࢖͍෼͚͕ඞཁʹͳΔ (each: for, map: list comprehension)
  13. ಺෦ΠςϨʔλ (Internal Iterator) • Ruby͸ͪ͜Β͕جຊ • ܁Γฦ͠Λ੍ޚ͢Δ໾ׂ͕ίϨΫγϣϯΦϒδΣΫτ·ͨ͸ϝιουͷ಺෦ɺ ͭ·ΓΦϒδΣΫτଆʹ͋Δ • ࣮ମͱͯ͠͸ɺ܁Γฦ͠͝ͱʹ࣮ߦ͢Δؔ਺Λड͚औΔߴ֊ؔ਺

    • ཁૉ͝ͱͷίʔϧόοΫؔ਺Λॻ͚ͩ͘ͳͷͰɺఆܕͷϧʔϓॲཧͷهड़͸ͱ ͯ΋؆୯ • ෳ਺ͷίϨΫγϣϯΛಉظతʹᢞΊΔͳͲ͸ۤखʢ͋Δ͍͸ແཧʣ • each΋map΋ಉ͡ߏจͰॻ͚Δ (each & map share a common construct)
  14. Rubyͷ಺෦ΠςϨʔλ Internal Iterator In Ruby • each + Enumerable ΛAPIͱͯ͠શ໘࠾༻͍ͯ͠Δ

    • ߴ֊ؔ਺ͱͯ͠ͷ಺෦ΠςϨʔλΛ࢖͍΍͍͢Α͏ɺϒϩοΫͱ͍͏ಛ घߏจΛ༻ҙ • break, next ͳͲϧʔϓʹదͨ͠δϟϯϓ໋ྩΛఏڙ • ͞Βʹ return Ͱ֎ଆͷϝιου͔Β΋ൈ͚ΒΕΔ • ݁Ռͱͯ͠ɺ֎෦ΠςϨʔλͱḮ৭ͳ͍ॲཧͷදݱྗ
  15. Rubyͷ֎෦ΠςϨʔλ External Iterator In Ruby • Ruby 1.8Ҏલ͸ඪ४తͳαϙʔτ͸ͳ͔ͬͨ • IOͳͲ͸ɺgets,

    eof?ͳͲͷʢ఻౷తͳʣ֎෦ΠςϨʔλܕ ͷAPI΋ఏڙ͍ͯ͠Δ • ഑ྻͳͲఴ͑ࣈΞΫηε͕Ͱ͖ΔίϨΫγϣϯͷ৔߹͸ɺࣗ ྗͰΠϯσοΫεม਺Λૢ࡞ͯ͠whileจͰճ͢ͳͲ
  16. ؔ࿈: Ruby 1.8ͷGenerator Ruby 1.8.1ʙ1.8.7ʹ͸ɺࢲ͕ॻ͍ͨ generator ͱ͍͏࣮ݧత ͳ֎෦ΠςϨʔλੜ੒ϥΠϒϥϦ͕ඪ४ఴ෇͞Ε͍ͯ·ͨ͠ɻ (2003-2008)

  17. ؔ࿈: Ruby 1.8ͷGenerator • Generator: converts an internal iterator to

    an external iteretor • ۩ମతʹ͸ɺEnumerableΦϒδΣΫτΛ౉͢ͱɺnextϝιουΛݺͿ౓ʹ͔ͦ͜Β ཁૉ͕ॱʹฦΔΦϒδΣΫτΛ࡞Δ • callcc (!)Λ࢖͍ɺ಺෦ΠςϨʔλͷ܁Γฦ͠ΛࢭΊͨΓ࠶։੍ͯ͠ޚΛୣ͏߽շͳ ࣮૷ ! • ޙʹThreadʹΑΔϦϥΠτ΋ࢼΈΒΕͨ • ͍ͣΕʹͤΑɺຖճ܁Γฦ͠ΛࢭΊͯ͸࠶։ ͢ΔͷͰΦʔόʔϔου͕͍͢͝ • SyncEnumerator: GeneratorΛ࢖ͬͯෳ਺ͷ಺෦ΠςϨʔλΛಉظతʹ܁Γฦ͢ (lazyͳ zip)
  18. Generatorͷ࢖༻ྫ 2ͭʢҎ্ʣͷίϨΫγϣϯΛಉظతʹϧʔϓॲཧͰ͖Δɻ require "generator" array1 = ["A", "B", "C", "D"]

    array2 = ["A", "B", "D", "C"] g1 = Generator.new(array1) g2 = Generator.new(array2) loop do e1 = g1.next e2 = g2.next # compare elements, etc. end
  19. eachͰ΋2ͭͷ഑ྻͷ֤ཁૉΛൺֱ͍ͨ͠ ෳ਺ͷeach͸ಉظͰ͖ͳ͍ ! array1 = ["A", "B", "C", "D"] array2

    = ["A", "B", "D", "C"] array1.each do |e1| array2.each do |e2| # gets all combinations end end
  20. eachͰ΋2ͭͷ഑ྻͷ֤ཁૉΛൺֱ͍ͨ͠ ยํ͚ͩ಺෦ΠςϨʔλΛ࢖͍ɺ΋͏Ұํ͸ఴ͑ࣈΞΫηε͢Ε͹Մೳ array1 = ["A", "B", "C", "D"] array2 =

    ["A", "B", "D", "C"] array1.each_with_index do |e1, i| e2 = array2[i] # This is OK end ͨͩɺఴ͑ࣈΞΫηεͰ͖ͳ͍ΠςϨʔλಉ࢜ͷ৔߹͸͍ͬͨΜ഑ྻԽ͢ΔͳͲͷલॲཧ͕ඞཁɻ ·ͨɺঢ়گʹΑͬͯยํ͚ͩϙΠϯλΛਐΊΔɺͷΑ͏ͳॲཧ͸Φϑηοτͷ؅ཧ΋ඞཁʹͳ Δɻ
  21. ྻڍ͍Ζ͍Ζ

  22. ྻڍ͍ͨ͠΋ͷ͍Ζ͍Ζ Things To Enumerate ϋογϡʢHashʣͷ৔߹: • Ωʔͱ஋ͷ૊ʢpairʣ • Ωʔʢkeyʣ •

    ஋ʢvalueʣ
  23. ྻڍ୯Ґ͍Ζ͍Ζ Units For Iteration จࣈྻʢStringʣͷ৔߹: • ࿦ཧߦʢlineʣ • όΠτʢbyteʣ •

    ʮจࣈʯʢcharʣ • ίʔυϙΠϯτʢcodepointʣ • ॻهૉΫϥελʢgrapheme clusterʣ • ͦͷଞɺޠʢwordʣɺจʢsentenceʣɺஈམʢparagraphʣɺ෺ཧߦʢphysical lineʣͳͲ΋ߟ͑ΒΕ Δɻ
  24. Enumeratorͷ஀ੜ·Ͱ

  25. Enumerable͕ఏڙ͖ͯͨ͠໾ׂ • ಺෦ΠςϨʔλͷϑϨʔϜϫʔΫ (framework for internal iterators) • Ϋϥεʹinclude͢Δʢmix-inʣ •

    ͦͷΫϥεͷeachΛ֦ு͢Δ
  26. Mix-inͱͯ͠ͷݶք • includeͰ͸each͔֦͠ுͰ͖ͳ͍ʂ (Enumerable can only extend each) • each_byte΍each_keyͰ΋map΍select͍ͨ͠

    • ഑ྻ(Array)Խͯ͠΍Ε͹Ͱ͖Δ͚Ͳɺͨͱ͑͹findͷΑ͏ʹ1ͭݟ͔ͭͬ ͨΒ࢒Γ͸ཁΒͳ͍ɺͱ͍͏ͱ͖͸ඇޮ཰ (Intermediate arrays require memory) • ObjectSpace.each_objectͷΑ͏ʹϞδϡʔϧϝιου͕ΠςϨʔλɺ ͱ͍͏ྫ΋͋Δ (ObjectSpace is not an enumerable object, yet provides an iterator method)
  27. EachDelegatorͱ͍͏ൃ૝ Ԭా ५͞Μ࡞ͷEachDelegator (2001) ࢦఆͨ͠ΠςϨʔλϝιουΛॻ͖׵͑ɺϒϩοΫͳ͠Ͱݺͼग़͞ΕͨΒEnumerableͳΦϒ δΣΫτΛฦ͢ɺʮϒϩοΫͳ͠eachʯͷઌߦఏҊ require "eachdelegator" class String

    each_delegator :each_byte end "͋".each_byte.each_with_index.collect { |byte, i| [i, "%02X" % byte] } #=> [[0, "E3"], [1, "81"], [2, "82"]]
  28. EnumeratorͷൃҊ • ͜ͷΞΠσΞʹײ໏Λड͚ͨࢲ͸ɺEnumeratorΛఏҊ (May 2001) • [ruby-list:29604] Importing eachdelegator.rb •

    [ruby-list:29624] Enumerator • [ruby-dev:13202] Re: [ruby-list:29672] Re: Enumerator • [ruby-dev:13259] Enumerator -- Round 2 • Enumerable::EnumeratorΫϥεΛઃ͚ɺ Kernel#enum_with(:each_xxx) ͰͦͷΠϯελϯεΛฦ͢ͱ͍͏಺༰ • each_xxx ϝιουΛࢧԉ͍ͨ͠
  29. Enumeratorͷ࠾༻ Ruby 1.8.1ʹඪ४ϥΠϒϥϦͱͯ͠࠾༻ (Oct 2003) • ͜ͷ࣌఺Ͱ͸ɺ·ͩrequire "enumerator"͕ඞཁͳҰϥΠϒϥϦ • ૊ΈࠐΈͰ͸ͳ͍ͷͰɺඪ४ΫϥεͷeachͰEnumerator͕ฦΔͱ͍

    ͏ػೳ΋ͳ͠ • enum_with / each_for ͰϝιουΛࢦఆͯ͠࢖͏ • ͜͜Ͱɺ܁Γฦ͠ॲཧҰൠΛ֦ு͢ΔػೳΛ2ͭಋೖͨ͠
  30. ܁Γฦ͠ͷ֦ு • ࢦఆݸ਺ͣͭͷεϥΠε (each_slice) • ࿈ଓཁૉͷ܁Γฦ͠ (each_cons)

  31. ࢦఆݸ਺ͣͭͷεϥΠε each_slice(n)Ͱnཁૉͣͭ·ͱΊͯ܁Γฦ͢ # 100௨ͣͭλεΫԽ recipient_ids.each_slice(100) do |ids| MessageJob.perform_later(ids: ids) end

  32. ࿈ଓཁૉͷ܁Γฦ͠ each_cons(n)Ͱʮ֤ཁૉ+ޙଓͷܭnཁૉʯʹ͍ͭͯ1ͭͣͭ ͣΒ͠ͳ͕Β܁Γฦ͢ [1, 2, 3, 4, 5, 6].each_cons(3) do

    |es| p es end # [1, 2, 3] # [2, 3, 4] # [3, 4, 5] # [4, 5, 6]
  33. ࿈ଓཁૉͷ܁Γฦ͠ • nilຒΊͤͣʹ (size - n + 1) ճ܁Γฦͯ͠ऴΘͬͯ͠· ͏ͷͰɺʮίϯςΩετ෇͖܁Γฦ͠ʯͱͯ͠࢖͏ʹ͸

    ͪΐͬͱ଍Γͳ͍ • ͨͱ͑͹࠷ॳʹ [nil, 1, 2]ɺ࠷ޙʹ [5, 6, nil] Λ଍ ͯ͘͠ΕΕ͹શཁૉͷલޙίϯςΩετ෇͖܁Γฦ͠ʹͳΔ ͷʹ… ! Ruby 2.6ͷchainͰٹࡁ͞Ε·͢ʂʢޙड़ʣ
  34. Ruby 1.9ͷ։ൃ͕ਐΉ ෳ਺ͷେ͖ͳมߋΛؚΉRuby 1.9ͷ։ൃ͸͔ͳΓ೉ߤͨ͠ • ΠϯλϓϦλͷࠩ͠ସ͑ʢYARVʣ • ਖ਼نදݱΤϯδϯͷมߋʢَं Onigurumaʣ •

    CSIํࣜͷM17Nಋೖ • ৽จ๏ ({ key: value }, -> {}) etc.
  35. ΠϯλϓϦλͷࠩ͠ସ͑ʢYARVʣ • VMͷಋೖ • OSͷωΠςΟϒεϨουΛ࢖͏Α͏ʹ (pthread) • ThreadΑΓܰྔͳίϧʔνϯػߏ (Fiber)

  36. ༨ஊ: ਖ਼نදݱΤϯδϯͷมߋ • ৽ͨʹॻ͖ى͜͞ΕͨΤϯδϯʮَंʯ(Oniguruma) by K.Kosako • ͦΕ·Ͱ͸GNU regexϥΠϒϥϦΛ(ຐ)վ଄ͯ͠࢖͍ͬͯͨ •

    Perl֦ுΛ͕Μ͹࣮ͬͯ૷͖͕ͯͨ͠ɺ֦ுੑʹ΋ݶք • ϥΠηϯε͕͚ͩ͜͜LGPLͩͬͨͷͰऔΓѻ͍ʹ஫ҙΛཁͨ͠ • RubyͰ͸ະ࣮૷ͩͬͨPerlޓ׵ͷ௥ՃػೳΛ΄΅͢΂ͯඋ͑ɺBSDL Ͱɺ֦ுੑɺੑೳʹ΋༏Ε͍ͯͨ • ݱࡏ(2012-)͸ޙܧͷʮَӢʯ(Onigmo)ʹͳ͍ͬͯΔ
  37. ༨ஊ: CSIํࣜͷM17Nಋೖ • Code Set Independentํࣜ • ݸʑͷStringΦϒδΣΫτ͕ࣗ਎ͰΤϯίʔσΟϯά৘ใΛ࣋ͪɺෳ ਺ͷΤϯίʔσΟϯάͷจࣈྻσʔλ͕ࠞࡏͰ͖Δ •

    ͋·ΓଞͷݴޠʹྨΛݟͳ͍ • ಺෦ΤϯίʔσΟϯά͸UTF-8ͷΈʹ౷Ұ͢Δͷ͕ʢ౰࣌Ͱ΋ʣେ੎ • ͍͍ͤͥબ΂ͯ΋1ͭͷΈ • َंͷෳ਺ΤϯίʔσΟϯάରԠ෦͕ૅͱͳ͍ͬͯΔ
  38. Enumeratorͷ ૊ΈࠐΈԽͱ੒௕

  39. Enumeratorͷ૊ΈࠐΈԽ • ext/enumerator ͔ΒτοϓϨϕϧʹҠಈ͠ɺσϑΥϧτͰϩʔυ͞ΕΔΑ ͏ʹ (2005) • require͕ෆཁʹ ! •

    ૊ΈࠐΈΫϥεʹʮϒϩοΫͳ͠eachʯ͕࣮૷͞ΕΔ • Ruby 1.9ͷFiberΛར༻ͯ͠next, next?, rewind͕࣮૷͞ΕΔ (Aug 2007) ͍ͭʹEnumerator͕֎෦ΠςϨʔλ݉༻ʹʂ (Enumerator became usable as an external iterator) • ͜ΕͰGenerator͸ແࣄҾୀ "
  40. Enumeratorͷਖ਼ࣜͳ૊ΈࠐΈԽ • Ruby 1.9.0-devϦϦʔε ! (Dec 2007) • 1.8ܥʹ΋όοΫϙʔτ͞Εࢲ͕ͯ͠ɺRuby 1.8.7ϦϦʔε

    (Jun 2008) ΍͕ͯདྷΔ1.9.1ͱͷΪϟοϓΛݮΒ͔ͨͬͨ͠ • 1.9.1Ͱͷ҆ఆ൛ϦϦʔεΛ߇͑ɺ͞Βʹ͔͜͜ΒEnumeratorͷ࢓༷٧Ί͕ਐΉ… • ϝϞΦϒδΣΫτͷ෇Ճػೳ (Iteration with a memo object) • ΠϯσοΫεͷ෇Ճ (Iteration with an index number)
  41. Iteration With A Memo Object ϧʔϓ಺ʢ͚ͩʣͰڞ༗Ͱ͖ΔΦϒδΣΫτΛ࣋ͪɺͦ͜ʹ৘ ใΛू໿ͯ݁͠Ռ஋ͱͯ͠ಘ͍ͨ result = {}

    records.each do |record| result[record.id] = record end p result # એݴ/ॳظԽɺૢ࡞ɺࢀরͷ3εςοϓΛ·ͱΊ͍ͨ
  42. Iteration With A Memo Object inject/reduceΛ࢖͏ͱͰ͖Δ͕ɺϒϩοΫͷฦΓ஋Λҙࣝ͠ ͳ͍ͱ͍͚ͳ͍ result = records.inject({})

    { |hash, record| hash[record.id] = record hash # ͋·Γ͜ΕΛॻ͖ͨ͘ͳ͍ }
  43. Iteration With A Memo Object Enumerator#with_memoͷ໊લͰఏҊͨ͠ (Jun 2008) • [ruby-core:17084]

    Enumerable::Enumerator#with_memo • ࠷௿ݶͷهड़Ͱ࣮ݱͰ͖Δ result = records.each.with_memo({}) { |record, hash| hash[record.id] = record } • with_object, with_obj, withͳͲͷҊ΋ఴ͑ɺͦͷޙɺintroduceͱ͍͏͔͍͍ͬ͜Ҋ ΋ग़ͨ͠ • ͔͠͠ͳ͔ͳ͔ܾΊ͖Εͣɺແ೉ͳ each_with_object ͱ͍͏໊લͰೖΕͯ৸͔ͤΔ͜ͱ ʹͨ͠ ! (To be continued)
  44. Iteration With An Index Number • each_with_index͸͋Δ͕ɺ։࢝஋͕0ݻఆͳͷͰɺoriginΛࢦఆ͍ͨ͠ [ruby-dev:37921] with_index_from by

    mame͞Μ (2009) • ࠓ·Ͱ͸ࣗ෼ͰΦϑηοτΛ଍͍ͯͨ͠ file.each_with_index do |line, i| print "#{i+1}: #{line}" end • each_with_indexʹҾ਺Λ଍͔͕ͨͬͨ͠ɺeach_with_indexʹ౉͞ΕͨҾ਺͸ͦͷ ··eachʹ౉ΔΑ͏ʹͳ͍ͬͯΔ • ͨͱ͑͹String#each͸ΦϓγϣφϧҾ਺Ͱվߦʹ୅ΘΔ۠੾ΓจࣈΛࢦఆͰ͖Δ
  45. Iteration With An Index Number • each_with_index͸ͦͷ··ʹɺ Enumerator#with_index͚֦ͩு͢Δ͜ͱʹͯ͠࠾༻ (Feb 2009)

    file.each.with_index(1) do |line, i| print "#{i}: #{line}" end
  46. Ruby 1.9ͷҰൠ޲͚ϦϦʔε ͦͯ͠ؾ͕෇͘ͱ… Ruby 1.9.1ϦϦʔε ! (Jan 2009) • एׯෆຊҙͳ͕Βɺ

    each_with_object / with_object ͕ͦͷ໊લͰ֬ఆ͢Δ͜ͱʹ ! • ௕͍ͳ͋ͱࢥ͏ਓ΋ଟ͍ͱࢥ͍·͕͢ɺ͜͏͍͏ࣄ৘Ͱ͠ ͨ
  47. Enumeratorͷ ͞ΒͳΔൃల

  48. Enumeratorͷ͞ΒͳΔൃల • ஗ԆධՁ (Lazy Iterators) • ࣗ༝ͳྻڍ (Freehand Iterators) •

    ΠςϨʔλͷ࿈࠯ (Chaining Iterators)
  49. Lazy Iterators • find, any?, all?ͳͲɺ৚݅ʹ߹͏ʢ߹Θͳ͍ʣཁૉ͕ग़ݱͨ͠Βଧͪ੾Γɺͱ͍͏ Enumerableͷϝιου͕৭ʑ͋Δ • map΍selectΛ࿈࠯ͤ͞Δͱ͖ɺຖճ഑ྻΛ࡞Δͷ͸ۭؒޮ཰͕ѱ͍ •

    ू໿͍ͨ͠৔߹ɺೖΕ෺Λ༻ҙ͢Δͷ͸࠷ޙ͚ͩͰे෼ͳ͸ͣ • ͦ΋ͦ΋ɺϑΟϧλϦϯά͚͕ͩඞཁͰɺू໿ࣗମ͸ෆཁͳ͜ͱ΋ଟ͍ • [Feature #4653] Enumerable#rude_map by shyouhei (May 2011) • [Feature #4890] Enumerable#lazy by yhara (Jun 2011) • Ruby 1.9.3ʹ͸ؒʹ߹Θͣ (Oct 2011) • Ruby 2.0ͰEnumerable#lazy͓ΑͼEnumerator::Lazy͕࠾༻ (Feb 2013)
  50. Freehand Iterators • ΠςϨʔλΛ࣮૷͢Δʹ͸ɺeachϝιουΛఆٛ͢Δɺ͕جຊ • ͦͷ৔ͰEnumerableͳΦϒδΣΫτΛ࡞ͬͯฦ͍ͨ͠ɺͱ͍͏ͱ͖ɺ Object.newͯ͠.extend(Enumerable) ͯ͠ಛҟϝιουeachΛੜ ΍͢ɺͱ͍͏ͷ͸͋·ΓΧδϡΞϧʹ΍Γͨ͘ͳ͍ •

    EnumeratorΛ࡞ͬͨͱ͖ɺEnumerableͷ֦ுधཁͷύϯυϥͷശΛ։ ͘͜ͱʹͳΔͱ༧ݟͨ͠ "# • ԿͰ΋Ͱ͖Δ΋ͷ΋ඞཁͩΖ͏…ͱ Enumerator.new {} Λ͓·͚ ͰೖΕͨ
  51. Chaining Iterators Enumerator#+ ͕΄͍͠ɺͱ͍͏ཁ๬͕དྷͨͱ͖΋… • [Feature #709] Enumerator#+ (Nov 2008)

    by candlerb ʮ͜ΕͰҰԠͰ͖ΔΑʯ Enumerator.new { |y| collection1.each { |x| y << x } collection2.each { |x| y << x } }.each do |x| # Enumerates collection1, and then collection2 end
  52. Chaining Iterators ͱ͍͏Θ͚ͰɺҎԼͷཧ༝͔ΒҰճݟૹΒͤͯ΋Βͬͨ • ԋࢉࢠϝιουΛ͋·Γ҆қʹೖΕΔͱ͋ͱͰଞͷԋࢉࢠͱ ͷ੔߹ੑͰۤ࿑ɾޙչ͢Δ • Ϣʔεέʔε͕Ͳͷ͘Β͍͋Δ͔·ͩ໌Β͔Ͱͳ͍ • ࠓ͸Enumerator.new

    {}Ͱखॻ͖ͯ͠Ͷ
  53. Chaining Iterators, A Decate Later • ͦͯ͠े೥ޙɺࠓ౓͸chainͱ͍͏໊લͰఏҊ͕དྷͨ [Feature #15144] Enumerator#chain

    (Sep 2018) by zverok • ͦͷࠒʹ͸ɺࢲࣗ਎ͷܦݧ͔Β΋࿈࠯ͷϢʔεέʔε͸۩ ମతʹݟ͍͑ͯͨ !
  54. Chaining Iterators, A Decate Later • ૝ఆͰ͖ΔϢʔεέʔε • ྫ: ίϚϯυϥΠϯΦϓγϣϯͰͷࢦఆɺ؀ڥม਺ͷ஋ɺઃఆϑΝΠϧ಺ͷઃఆ

    ஋ɺͷॱʹݕࡧύεΛฦ͢ • ྫ: ࠷৽ͷߋ৽σʔλΛAPI͔ΒҾͬுͬͯฦ͠ɺଓ͍ͯϩʔΧϧετϨʔδʹ Ωϟογϡ͞Εͨ෦෼Λฦ͠ɺ͞ΒʹͦΕҎલͷ΋ͷ͕ඞཁͳΒAPI͔ΒҾ͍ͯฦ͢ • first(3), take_while, find ͳͲͰޮՌΛൃش • ୯७ʹɺ഑ྻΛ࡞Δ͜ͱͳ͘ෳ਺ͷετϦʔϜΛॱ࣍૸͍ࠪͨ͜͠ͱ͸࣮ࡍʹଟ͍ • શ߲໨૸ࠪ͢Δ৔߹Ͱ΋ޮ཰త ✨
  55. Chaining Iterators, A Decate Later • MatzΛަ͑ͨٞ࿦Ͱ΋ɺ Enumerator#+ ΛׂΓ౰ͯͯ΋໰ ୊ͳ͔Ζ͏

    ! ͱͳͬͨ • chain ͸ Enumerable ʹ͋ͬͯ΋͍͍ΑͶɺͱͳΓɺ͋Θ ͤͯRuby 2.6Ͱ࠾༻ "
  56. Example: chain + each_cons = Contexual Iteretion a = ["foo",

    "bar", "baz"] [nil].chain(a).each_cons(2) do |prev, curr| if prev.nil? puts "#{curr} comes first." else puts "#{curr} comes after #{prev}." end end # Output: foo comes first. bar comes after foo. baz comes after bar.
  57. Ruby 2.7Ҏ߱ͷ ల๬ͱ՝୊

  58. Ruby 2.7Ҏ߱ͷల๬ͱ՝୊ • Enumerator::Yielder#to_proc • Enumerator.generate • Multi-Value Or Array?

    • Lazy: Back To Eager?
  59. Enumerator::Yielder# to_proc

  60. Enumerator::Yielder#to_proc • [Feature #15618] Enumerator::Yielder#to_proc (Feb 2019) by knu Enumerator#to_procΛ࣮૷͢Δ͜ͱͰ

    enum = Enumerator.new { |y| Dir.glob("*.rb") { |file| File.open(file) { |f| f.each_line(&y) } # File.open(file) { |f| f.each_line { |line| y << line } } } } ͱॻ͚ΔΑ͏ʹ͢ΔఏҊ • Ruby 2.7Ͱ࠾༻ !
  61. Enumerator.generate

  62. Enumerator.generate • [Feature #14781] Enumerator.generate (May 2018) by zverok •

    Ұͭલͷ஋͔Β࣍ͷཁૉΛܾఆ͢Δ܁Γฦ͠ • ਺ֶͰ͍͏ʮ઴ԽࣜʯʹΑΔ܁Γฦ͠ఆٛ • ϊʔυͷ parent ΛॱʹḷΔͱ͔ • ϦτϥΠͷ଴ͪ࣌ؒΛഒʑʹ͍ͯ͘͠ͱ͔ • ݕ౼ࣄ߲ • ऴྃ৚݅ͷࢦఆํ๏ʢಛఆͷྫ֎ͰऴΘΔͷ͔ɺnilͰऴΘΔͷ͔ɺͦͷ৔߹nilΛؚΉͷ͔ʣ • 2ͭҎ্લ΋ࢀর͍ͨ͠ʁʢྫ: ϑΟϘφον਺ྻ… ͋·Γݱ࣮ʹ͸ͳ͍ʁʣ
  63. Multi-Value Or Array?

  64. Multi-Value Or Array? • Hash#each / map ͸ϖΞΛ1Ҿ਺Ͱ2ཁૉ഑ྻΛϒϩοΫʹ౉ͯ͘͠Δ [1] pry(main)>

    {foo: 1, bar: 2, baz: 3}.each{|x| p x} [:foo, 1] [:bar, 2] [:baz, 3] => {:foo=>1, :bar=>2, :baz=>3} [2] pry(main)> {foo: 1, bar: 2, baz: 3}.map{|x| p x} [:foo, 1] [:bar, 2] [:baz, 3] => [[:foo, 1], [:bar, 2], [:baz, 3]]
  65. Multi-Value Or Array? • Hash#select / reject ͸ϖΞΛ2Ҿ਺ͰϒϩοΫʹ౉ͯ͘͠Δ [3] pry(main)>

    {foo: 1, bar: 2, baz: 3}.reject{|x| p x} :foo :bar :baz => {} [4] pry(main)> {foo: 1, bar: 2, baz: 3}.select{|x| p x} :foo :bar :baz => {:foo=>1, :bar=>2, :baz=>3}
  66. Multi-Value Or Array? • ͜ͷҧ͍͸Ͳ͔͜Βʁ • Hash#each / map ͸ϖΞΛ2ཁૉ഑ྻ1ͭΛϒϩοΫʹ౉ͯ͘͠Δ

    (yield [key, value]) • Hash#select / reject ͸ϖΞΛ2Ҿ਺ͰϒϩοΫʹ౉ͯ͘͠Δ (yield key, value) • Hash#select / reject ͸ɺRuby 1.8·Ͱ͸ArrayΛฦ͢ϝιου͕ͩͬͨɺ1.9͔ ΒHashΛฦ͢Α͏ʹมߋ͞Εͨ • ͦͷͱ͖ʹɺҙਤ͔ͯ͠஌Β͔ͣ2Ҿ਺Ͱ౉͢Α͏ʹͳͬͨ • ࠓ͞Β௚ͤͳ͍ͱͯ͠ɺmulti-value㱻arrayͷ૬ޓม׵͸धཁ͕͋Δ͔΋
  67. Multi-Value Or Array? • λϓϧͷ֤ཁૉʹରͯ͠ɺͦΕͧΕϝιουΛద༻͢Δྫ require "csv" line = "10,foo,3.14"

    modifiers = [:to_i, :to_s, :to_f] # "10".send(:to_i), "foo".send(:to_s), "3.14".send(:to_f) Λظ଴… p CSV.parse_line(line).zip(modifiers).map(&:send) #=> no method name given (ArgumentError) • ࣮ࡍʹ͸ ["10", :to_i].send, … ͕࣮ߦ͞Εͯ͠·͏
  68. Multi-Value Or Array? ΋͠array→multi-valueʹม׵͢Δػೳ͕͋Ε͹… module Enumerable def each_splat return to_enum(__method__)

    unless block_given? each { |a| yield(*a) } end end
  69. Multi-Value Or Array? ͏·͍͘͘ ! require "csv" line = "10,foo,3.14"

    modifiers = [:to_i, :to_s, :to_f] p CSV.parse_line(line).zip(modifiers).each_splat.map(&:send) #=> [10, "foo", 3.14]
  70. ͪͳΈʹ… • CSVʹ͸convertersͱ͍͏͢͹Β͍͠ػೳ͕͋Γ·͢ʂ line = "10,foo,3.14" modifiers = [:to_i, :to_s,

    :to_f] p CSV.parse_line(line, converters: ->(value, field) { value.send(modifiers[field.index]) }) #=> [10, "foo", 3.14] • ͱ͍͏Θ͚Ͱઆಘʹ࢖͏ʹ͸ద͞ͳ͍ϢʔεέʔεͰͨ͠
  71. Lazy: Back To Eager?

  72. Lazy: Back To Eager? • Ұ౓lazyʹ͢Δͱɺී௨ͷ(eagerͳ)Enumeratorʹ͸໭ͤͳ͍ lazy = [1, 2,

    3].lazy # Expecting #each would create a normal Enumerator... still_lazy = lazy.each # Not: Enumerator::Lazy#each is overridden to return a Lazy # Not usable as a normal Enumerator p still_lazy.map { |x| x * 2 } #=> #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map> • lazyΛۦ࢖ͯ͠࡞ͬͨEnumeratorΛɺmap͢Δͱ഑ྻ͕ฦΔΑ͏ͳ;ͭ͏ͷEnumerableΦϒδΣΫτ ͱͯ͠ฦ͍ͨ͠
  73. Enumerator::Lazy#eager (Ҋ) ΋͠lazyͰͳ͍Enumeratorʹม׵͢Δػೳ͕͋Ε͹… class Enumerator::Lazy def eager Enumerator.new { |y|

    each { |x| y << x } } end end
  74. Lazy: Back To Eager? ͏·͍͘͘ ! lazy = [1, 2,

    3].lazy eager = lazy.eager # Usable as a normal enumerable object p eager.map { |x| x * 2 } #=> [2, 4, 6]
  75. ·ͱΊ

  76. ·ͱΊ • ΈΜͳେ޷͖Enumerable͸ͲΜͲΜਐԽ͖ͯ͠·ͨ͠ɻ • EnumeratorͷಋೖʹΑΓɺ७ਮʹ܁Γฦࣗ͠ମͷݚڀ͕ਐΈ·ͨ͠ɻ • ࠓ΋ਐԽ͍ͯ͠·͢ʂ • ࠓޙ΋ɺݱ࣮ͷχʔζΛ౿·͑ͯʮ΄͍͠ʂʯػೳΛ֦ॆ͍͖ͯ͠·͢ʂ •

    ࠷ۙ͸RubyͷϦϦʔεαΠΫϧ͕ߴ଎Խ͍ͯ͠ΔͷͰɺ͋ͳͨ΋ཁ๬Λग़ͤ͹ ೥຤ʹ͸۩ݱԽ͢Δ͔΋ʂ • ΫϦεϚεϓϨθϯτ ! • ϚνϚνͰҰॹʹಇ͘஥ؒΛืू͍ͯ͠·͢ʂ