LoginSignup
2
2

More than 3 years have passed since last update.

Elixir ~Enum.mapをEnum.mapで包む~

Posted at

ここまでのあらまし

前回のドキュメントElixir~名前付き関数とモジュール化~ でEnum.mapで各要素をIO.putsで出力することをしました。

今回は、Enum.mapにEnum.mapを入れ子にするとどうなるか、やってみようと思います。

本題

適当なディレクトリで

mix new example

します。

式はこちら

lib/example.ex
defmodule E do
  def example( list ) do
    list
    |>Enum.map( & F.foo(&1) )
  end
end

defmodule F do
  def foo(list2) do
    Enum.map(list2, fn x -> x * 2 end)
  end
end

(あまり関数の命名が美しくないかもしれませんが、お許しください。。)
Enum.mapで各要素に対して下段のEnum.を呼び出し、それぞれの要素に2をかける、というものです。

最初はEnum.mapに対してEnum.mapを入れ込むことは適当じゃないのだろうか、という問いから出発し、
まずはでは式を作ってみよう、ということでこの式を作りました。

さっそくiexで[1,3,5]のリストを引数に関数exampleを呼び出してみます。

iex > E.example([1,3,5])
** (Protocol.UndefinedError) protocol Enumerable not implemented for 1. This protocol is implemented for: HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream
    (elixir) /private/tmp/elixir-20190202-21222-1ilp2g0/elixir-1.8.1/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) /private/tmp/elixir-20190202-21222-1ilp2g0/elixir-1.8.1/lib/elixir/lib/enum.ex:141: Enumerable.reduce/3
    (elixir) lib/enum.ex:3015: Enum.map/2
    (elixir) lib/enum.ex:1327: Enum."-map/2-lists^map/1-0-"/2

?????????
"加算プロトコルは1のために実装されていない。このプロトコルは〜〜〜"

普通に整数のリストを与えても上記エラーが出ます。

iex > E.example([false , "first" ,123])
** (Protocol.UndefinedError) protocol Enumerable not implemented for false. This protocol is implemented for: HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream
    (elixir) /private/tmp/elixir-20190202-21222-1ilp2g0/elixir-1.8.1/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) /private/tmp/elixir-20190202-21222-1ilp2g0/elixir-1.8.1/lib/elixir/lib/enum.ex:141: Enumerable.reduce/3
    (elixir) lib/enum.ex:3015: Enum.map/2
    (elixir) lib/enum.ex:1327: Enum."-map/2-lists^map/1-0-"/2

リストの中身を真偽値や文字列にしても同じエラーに阻まれました。
???????????

次いで、関数fooの動作確認をします。

iex > F.foo([1,3,5])
[2, 6, 10]

こちらは式のとおりリストの各要素にかける2をした値が返ってきました。

次いで、関数exampleにリストで包んだリスト、[[1, 2], [3, 4]]を与えてみます。

iex > E.example([[1, 2], [3, 4]])
[[2, 4], [6, 8]]

しっかりリストのなかの整数にすべて2をかけた値が返ってきました。

これは何を意味するのか?

ここで先生から重要なことを教わりました。

"Enum.mapにただの整数を渡すとエラーになる"

ということです。

つまり、Enum.mapにEnum.mapを入れ子にした関数では、
上段のEnum.mapで一度リストが各要素にバラされてしまうので、

"リストをリストで包んだデータ"を与えてやらねばならない

ということです。

ここからも先生の教えです。
この”リストをリストで包んだデータ”が何を意味するか。

これが意味するところのひとつは、表で表された数値データです。
[[1,2],[3,4]]は

|1|2|
|3|4|
のような表を表している。
このような表現を、数学では”行列"と呼ぶそうです。
また、いままでの数値を要素にしたリストを”ベクトル"と呼ぶ。
つまり、ベクトルを束ねたものが行列。
なお、リストのリストはC言語などでは"2次元配列"と呼ぶ。

つまり、
リスト=配列=ベクトル
リストのリスト=2次元配列=行列

というように対応する。
ここまで、先生の教えをうまく噛み砕けていないのですが、後から見返したときのために記述しておきます。

編集後記

前回IO.putsを入れ込んだところに自由に関数を当てはめることができる、また、Enum.mapのなかにEnum.mapを入れ込むことができる。

まだまだ、Elixirに限らずとも自分の自由な思考でコードを書くことに至らず、速いと信じていた自分の学習スピードに疑問を持つこともあります。
Qiitaドキュメントも、誤った記述をしてはならないようなセルフプレッシャーが強く、わからないこともうまく表現できないことがままあります。
が、必ず備忘録として役に立つ日があとで来るので、なるべくすまさず素直な書き方ができたらなと思います。

うまずたゆまず、頑張ります。

Kento Mizuno

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2