ElixirのGETTING STARTED（10. Enumerables and Streams）をやってみた

# URL
http://elixir-lang.org/getting-started/enumerables-and-streams.html

# 試した環境
* Ubuntu Server 14.04 LTS 
* Erlang/OTP 18
* Elixir 1.0.4

# Enumerables

Elixirはenumerableという概念とその[Enum](http://elixir-lang.org/docs/stable/elixir/#!Enum.html)モジュールがある。
既にリストとマップの2つのenumeableを学んでいる。

```ex
iex> Enum.map([1, 2, 3], fn x -> x * 2 end) 
[2, 4, 6]
iex> Enum.map(%{1 => 2, 3 => 4}, fn {k, v} -> k * v end) 
[2, 12]
```

Enumモジュールはenumerableなアイテムを変形、ソート、グループ化、フィルタリング、検索するための非常に幅の広い関数を提供する。Elixirのコードで頻繁に利用するモジュールの一つ。

Elixirには、範囲の表現も用意されている。

```ex
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
```

Enumモジュールは異なるデータ型でも動作するように考えられている。APIは様々なデータ型で便利なものだけ制限されている。
特別な操作は、データ型で指定されるモジュールを使う必要がある。
例えば、リストの特定の場所へ要素をインサートしたい場合は、Listモジュールの```List.insert_at/3```関数を使う必要がある。

様々なデータ型で動作するため、Enumモジュールはポリモーフィックと言っっている。特に、Enumモジュールの関数は[Enumerableプロトコルを](http://elixir-lang.org/docs/stable/elixir/#!Enumerable.html)を実装したどんな型でも動作する。
次に、streamと呼ばれるenumerableの１つをみていく。

# Eager vs Lazy

Enumモジュールの関数はeagerである。多くの関数はリストで返却する。

```ex
iex> odd? = &(rem(&1, 2) != 0)        
#Function<6.54118792/1 in :erl_eval.expr/5>
iex> Enum.filter(1..3, odd?)
[1, 3]
```
これは、Enumで複数の操作を実行した時、結果に到達するまで、各操作は中間のリストを生成することを意味する。

```ex
iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000
```

上の例ではパイプラインの操作をしている。範囲でスタートし、範囲の各要素を3倍する。最初の操作は100_000アイテムのリストを返す。そして、リスト中の全ての奇数を残し50_000個のアイテムの新しいリストを生成する。最後に、それらの要素を足しあわせいる。


## The pipe operator

上記のコードに使われている```|>``` 記号はパイプ演算子である。これは単純に左側の式の出力を取得し、右側の関数に入力渡す処理をする。
Unixの ```|```演算子に似ている。この演算子の目的は、データが一連の関数によって変形される流れを強調することにある。
```|>``` 演算子がどのようにコードを整理するか見るため、上記の例を ```|>``` 演算子を使わないで書き直すと次のようになる。

```
iex> Enum.sum(Enum.filter(Enum.map(1..100_000, &(&1 * 3)), odd?))
7500000000
```
パイプ演算子については[ドキュメント参照](http://elixir-lang.org/docs/stable/elixir/#!Kernel.html#%7C%3E/2)

# Streams

Enumの代わりとして、遅延操作をサポートする[Streamモジュール](http://elixir-lang.org/docs/stable/elixir/#!Stream.html)
を提供している。

```ex
iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000
```

streamはlazy(遅延評価)で、composable(組み合わせ可能)なenumerablesである。
中間リストを生成する代わりに、streamはEnumモジュールへ渡した時にだけ呼び出される一連の処理を作成する。streamは大きかったり、無限かもしれないようなコレクションを扱う場合に有用。

上の例でみたたように、```1..100_000 |> Stream.map(&(&1 * 3))```は1..100_000の範囲に対してmapを処理する表現であるstreamというデータ型を返すので，lazyである。

```ex
iex> 1..100_000 |> Stream.map(&(&1 * 3))
#Stream<[enum: 1..100000, funs: [#Function<47.72687021/1 in Stream.map/2>]]> 
```

さらに、多くのstream演算子をパイプできるので、composableである。

```ex
iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000,
 funs: [#Function<47.72687021/1 in Stream.map/2>,
  #Function<51.72687021/1 in Stream.filter/2>]]>
```

Streamモジュールは引数にどんなenumerableでも受け付け、streamとして返却する。無限に可能性のあるstreamを作る関数も用意している。例えば、```Stream.cycle/1```は、与えられたenumerableを無限に繰り返すstreamを作成することに使われる。このようなstreamで、```Enum.map/2``` のような関数を呼ばないように注意しなければならない。この繰り返しは永遠に終わらない。

```ex
iex> stream = Stream.cycle([1,2,3])
#Function<10.72687021/2 in Stream.unfold/2>
iex> Enum.take(stream, 10)
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
```

一方、```Stream.unfold/2```は、与えられた初期値から値を生成することに使われる。

```ex
iex> stream = Stream.unfold("hełło", &String.next_codepoint/1)
#Function<10.72687021/2 in Stream.unfold/2>
iex> Enum.take(stream, 3)
["h", "e", "ł"]
```

その他の興味深い関数は、失敗の場合でもenumerationの前に正しく開き、終わったら閉じることを保証するリソースをラップするために使われる```Stream.resource/3```がある。例えば、ファイルをstreamするために使える。

```ex:test.txt
Hello Elixir
```

```ex
iex> stream = File.stream!("test.txt")
%File.Stream{line_or_bytes: :line, modes: [:raw, :read_ahead, :binary],
 path: "test.txt", raw: true}
iex> Enum.take(stream, 10)
["Hello Elixir\n"]
```

上の例は、選択したファイルの最初の10行を取得する。このようにstreamは大きなファイルやネットワークリソースのような遅いリソースを扱うのに大変役に立つ。

最初はEnumやStreamモジュールにある関数や機能の量は手強く感じさせるが
、その時々で慣れるだろう。最初はEnumモジュールに集中して、特に遅延が必要な遅いリソースや大きなリソース、無限の可能性があるコレクションを扱う場合をStreamを使うようにすれば良いだろう。