Part15:EnumerableとStream

海未「それでは今回はEnumerableとStreamについてです。どう訳せばいいのかよくわからないので、表記はこのままでいきますね」

海未「まずはEnumerableから始めます。列挙可能な、ということで、リストやマップはenumerableなデータ構造です」
凛「列挙可能という日本語がわからないにゃ」
海未「実用上は、これまでに出てきたEnumモジュールが使える、ということを理解すれば大丈夫でしょう」

海未「この2つはよく使われるリスト操作の例ですが、mapはリストの各要素に順番に、第2引数の関数を適用していくものです」
希「この前ウチが説明したやつやね」
海未「はい。それからreduceは、この例だとリストから値を順番に取りだして足し込んでいって、合計値を求めています」
凛「2つとも再帰で書けそうな感じだにゃ」
海未「まさにそれです。Enumに用意されている関数は、本来再帰で処理しなくてはならないコレクションの操作を簡単に書けるように設計されています」
凛「たしかに、mapもreduceもいちいち再帰で書いてたらめんどくさいにゃ」
海未「リストを例に取りましたが、Enumの関数はそれ以外にも使えます」

海未「これはマップに使った例です」
凛「おー、使い方同じにゃ」
海未「Enumerableプロトコルというものがあって、それを実装したデータ構造体はEnumモジュールの関数で処理できるようになります」
希「プロトコル?」
海未「プロトコルについてはまたいずれ。データ構造を定義するときに従うお約束、とでも思っていてください」

海未「少し話を変えて、パイプ演算子というのを見てみましょう」

希「UNIXのパイプかな」
海未「希の怪しげな知識は一切信用しません」
希「・・・別に海未ちゃんに迷惑かけたりしとらんやん・・・」
海未「とにかく。これは|>の左側を、右側の第1引数として渡すための演算子です」
凛「えーと、["うみ", "りん", "のぞ"]Enum.map(fn x -> x <> x end)の第1引数になるんだよね。ということは、Enum.map ["うみ", "りん", "のぞ"], fn x -> x <> x endにゃ!」
海未「そうです。そしてその結果が、次のreduceの第1引数になります」

海未「パイプを使わずに書き直すとこうなります」
希「パイプを使えば一時変数を挟まずに書けるんやね」

海未「では応用編です。Streamについて見てみましょう」

海未「実行すると」

凛「何が違うかわからないにゃ」
海未「実行結果は全く同じです。違いといえば、Enumモジュールの関数は処理結果のリストを返しますが、Streamモジュールの関数はstreamというデータ構造を返します」
凛「それで、何が違うの?」
海未「Streamは遅延評価されます。つまり、最後のEnum.to_listの呼び出しまで、リストの中身を列挙する処理は実行されないのです」
凛「よくわからないにゃ」
海未「たしかに、難しいところですから・・・。では、少し分かりやすくなるようにさきほどのコードを修正してみましょう」

海未「これで、処理の途中経過をプリントしてみます」

海未「違いがわかりますか?」
凛「わかるけどわからないにゃ」
希「実行順序が違うってことなんやろうけど・・・」
海未「まず上半分のEnumの方は、最初に全ての要素を列挙し、次にfilterの結果、次にmapの結果が出力されています。これは、mapやfilterは1回1回で処理が完結していて、毎回結果として中間リストを生成して、次の処理ではそのリストを改めて列挙しているということです」
希「この例やと5回列挙してるってこと?」
海未「そうなります。ですから、リストが大きかったり処理の数が多いとどんどん効率が悪くなります」
凛「難しいにゃ」
海未「まあ、私も調べるのにかなり手こずりましたし・・・。それで、Streamの方ですが、これは全部で1回だけしかリストの列挙を行っていません」
希「あー、ほの→こと→うみ、まできて、うみのところでfilterとmapまで一気に処理を終わらせてから先に進んでるんやな」
海未「その通りです。Streamは遅延評価ですから、処理の全容が判明してからリストの処理に無駄がないように処理手順を組み立てられる、と考えればいいでしょう」
希「わざわざEnum.to_listを呼ぶまで実行されないのはそういうことだったんやね」
凛「わかったようなわからないような・・・」
海未「慣れないうちはEnumを使っていればよいと思います。データ量やリソース要件で必要に迫られてくれば必然的にStreamを使わざるを得なくなりますし、その学習は遅延評価でもいいでしょう」
希(うまいこと言った)
凛(うまいこと言ったにゃ)

希「次回はウチやね。入出力まわりをやってみよか」


LINEで送る
Pocket


返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です