ruby2.0の遅延リスト(enumerator::lazy) #tsukubarb
Post on 28-May-2015
343 Views
Preview:
DESCRIPTION
TRANSCRIPT
Ruby2.0の遅延リスト2014/05/08 @gam0022
自己紹介
@gam0022
coins11(情報科学類4年)
NPAL(非数値処理アルゴリズム研究室)
COJT SW 5th(去年)
Ruby と C# が好き
自己紹介(TwinCal)
TwinCal
“TwinCal"ググれば出てくる
Twinsの履修情報から、Googleカレンダー・iCalの時間割を作成するWebサービス
自己紹介(大五郎Bot)
大五郎Bot
マルコフ連鎖でフォローユーザのツイートを学習して喋るBot
Rubyで実装
Favstar から BAN ←去年5月
自己紹介(大五郎Bot)3回目の凍結中 ←New(今ここ)
永久凍結の危機(フォローワーが5000くらいなので惜しい)
Rubyの遅延リスト
Ruby 2.0 から導入された遅延リスト
Enumerable#lazy というメソッド
その返り値の Enumerator::Lazy
について紹介
遅延リスト
遅延リストとは
Haskell などの一部の関数型言語では一般的に使われている
遅延評価といって、値が必要になるまで計算しないことによって、無限に続くリストも扱うことができる
使用例
lazy を付けると無限リストが扱える!
[1]
[2]
[1]はなぜダメか
(1..Float::INFINITY).map{|n| n*2}.first(5)
Enumerator#map -> Array
Enumerator#map は配列を返すメソッド
➡無限の長さの配列を生成しようとして死ぬ
first(5)は実行されない (map待ち)
[2]の解説
(1..Float::INFINITY).lazy.map{|n| n*2}.first(5)
Enumerator::Lazy#map -> Enumerator::Lazy
Enumerable#lazy はリスト(ArrayやRangeなど)をEnumerator::Lazy に変換するメソッド
Enumerator::Lazy#map も Enumerator::Lazy を返す
Enumerable#lazy -> Enumerator::Lazy
[2]の解説
(1..Float::INFINITY).lazy.map{|n| n*2}.first(5)
Enumerator::Lazy#first -> Array
Enumerator::Lazy#first でようやく値が評価される(Arrayになる)
Enumerator::Lazy の中身は force(to_a), first などが呼ばれるまで、値が評価されない
Enumerator#mapとEnumerator ::Lazy#map
[1]と[2]の map メソッドはそれぞれ全く別物
[1] Enumerator#map -> Array
[2] Enumerator::Lazy#map -> Enumerator::Lazy
定義されている場所も返り値の型も違う
lazy を付けると無限リストが扱えるという理解でも良いが、正しくは、Enumerator::Lazy に定義された lazy 版の map を呼び出している。
lazyを付ける不思議な仕様
なぜ、lazy を付けると map の動作が変わる不思議な動作にしたのか?
Enumerable#lazy を作った 原 悠 さんによると、
Enumerable モジュールには、lazy 版がほしくなるようなメソッドが map、select、reject、drop、... とたくさんある。
全部追加すると、Enumerable モジュールのメソッドが増えすぎる。
Enumerator::Lazy 名前空間を提供することによって、「lazy」というメソッド名をひとつ追加するだけで lazy 版の map や select などが使えるようにした。
http://magazine.rubyist.net/?0041-200Special-lazy
遅延リストが使える場面
遅延リストが有効に使える場面
数学的に無限長の数列を扱いたい
TwitterのTimeLine
巨大なファイル(の一部だけ処理したい)
遅延リストで綺麗なコード
従来の Range#each とかでも最初の例と同じことができるが、map が使えると綺麗・簡潔にコードが書ける
map, first というように各処理が抽象化されている方が読みやすい
まとめ
Enumerable#lazy はリスト(ArrayやRangeなど)を遅延リストEnumerator::Lazy に変換するメソッド
遅延リストを使うと、無限リストもシンプルに扱える
Enumerator::Lazy#map は Enumerator#map のlazy 版の全く別のメソッド
Enumerable#lazy と Enumerator::Lazy#map を積極的に使おう!
補足
継承関係が複雑なのでまとめました(細かい部分は省略)
BasicObjectKernelObject
Enumerable
Enumerator Enumerator::Lazy
{- lazy - map - select - first,…⋯
{- map - select - first,…⋯
Range
Array
lazy版に再定義
top related