いままでわからなかったこと
Enum.mapやFilterやパイプライン演算子はElixirドキュメントの写経で出てきた。
しかしそれを自分の頭で考えてコードを組み立てることができない。赤子のようだ!
本題
設問1
最初に[3, 9, 27]のリストをもとにして各要素を3倍したあとで、30より大きい要素を出力する
iex> [3, 9, 27, 81] |> Enum.map(& &1 * 3) |> Enum.filter(& &1 >= 30)
[81, 243]
mapでの乗法とfilterでのソートも、パイプライン演算子を数珠つなぎにすることで可能になっています。
設問2
1から10までの整数のリストをもとにして、各要素を2倍したあとで10より小さな値を抜き出してさらに各要素を二乗して出力する
iex> 1..10 |> Enum.map(& &1 *2) |> Enum.filter(& &1 <= 10) |> IO.inspect |> Enum.map(& &1 * &1)
[2, 4, 6, 8, 10]
[4, 16, 36, 64, 100]
途中でパイプライン演算子を挟みデバッグに使うIO.inspectを入れて[2,4,6,8,10]の途中経過を表示させています。
パイプライン演算子について
設問2をシンセサイザーに例えてみましょう。IO.inspectはここでは省略します。2段目のmapと3段目のfilterを入れ替えて結果を見てみましょう。
iex> 1..10 |> Enum.map(& &1 *2) |> Enum.filter(& &1 <= 10) |> Enum.map(& &1 * &1)
[4, 16, 36, 64, 100]
iex> 1..10 |> Enum.map(& &1 *2) |> Enum.map(& &1 * &1) |> Enum.filter(& &1 <= 10)
[4]
驚くべきなのか当然と片付けるべきかわからないのですがmapとfilterの内容を入れ替えると結果が変わりました。
これは、左辺のリストをエレキギターのコイルやシンセサイザーのオシレーターとしたら、のちにかけるフィルター(filter)やオーバードライブ(map)の順番によっていかようにも出音が変わることと共通しています。
ここまでの気づき
このエントリ自体はなんてことのないEnumの四則演算のパイプライン演算子ごとの順番入れ替えによって結果が変わることを図示したものですが、わたし自身音楽家であることもあり、"オシレーターとフィルターとLFOの順番違ったら音違うじゃん!それとElixirも一緒!って言われたら納得するな"と思い記事をしたためた次第です。