LoginSignup
9
3

More than 5 years have passed since last update.

Elixirのforはpythonのforとは違ったというお話

Last updated at Posted at 2018-02-28

弊社ではpythonを使った開発が主流ですが、ここ最近はelixirでの開発にも取り組んでおります。
そこでelixirの勉強をしているのですが、現時点で一番ハマったことを共有します。

問題

リスト[1, 2, 3, 4, 5]の各要素の合計を求めるプログラムを実装しなさい。
(ただし、Enum.sum()は使わない)

実装

pythonで実装したらどうなるかを考えて、それをelixirで書き直せばいいんじゃないかなと思った(のがそもそもの間違いだった)。

sample.py
total = 0
for i in [1, 2, 3, 4, 5]:
    total += i
print(total)

これをelixirで書くと・・・(なお、間違いです)

sample.ex
total = 0
for i <- [1, 2, 3, 4, 5] do
    total = total + i
end
IO.puts total

結果

IO.puts total は0でした。

なぜ?

かなり回りくどい書き方になってしまいますが、私が理解した順番に記述します。

スコープの問題だった

for の中と外でスコープが異なるため、IO.puts totalのtotalは、forの外側のtotalでした。

湧き上がる疑問

じゃぁforの中ではちゃんとリストの要素を足してるんだろうなぁ。

sample_2.ex
total = 0
for i <- [1, 2, 3, 4, 5] do
    total = total + i
    IO.puts total
end

結果

2018年2月-1.png
(本気で「!?」でした)

そもそもの誤解

generator.ex
for i <- [1, 2, 3, 4, 5] do
    ...
end

これはelixirではループではなく、[1, 2, 3, 4, 5]のリストから要素を取り出す、内包表記と呼ばれる記述方法でした。
なのでforの中で足し算するものの、毎回その結果は捨て去られている(という表現が適切かわかりませんが)。
ですので「スコープの問題だった」という見出しを作りましたが、根本的に間違っていたということになります。

で、elixirで実装するとしたら?

Enum.reduce()を使って

reduce.ex
total = Enum.reduce([1, 2, 3, 4, 5], fn(x, acc) -> x + acc end)
IO.puts total

と書く感じでしょうか。

ちなみに封じていたEnum.sum()は?

気になったので見て見たらこのように定義されてました。

enum_sum.ex
def sum(enumerable) do
    reduce(enumerable, 0, &+/2)
end

&+/2 とは一体・・・

なんすかこれ!?と思って調べたところ・・・

&記法

elixirでは無名関数をよく使うため、省略記法として、&記法というものがあるそうです。
&以降の式を関数に変換する演算子とのこと。
なので、「&+/2」は「+/2」という無名関数・・・「+/2」とは?

+/2

実現させたいのは2つの数の和です。
それは下記のように書けます。

summary.ex
fn x, y -> x + y end

この無名関数は引数が2つあって、それの単純に足しています。
これをelixirは &+/2 と書けてしまうのだそうです。
(ちなみに「/2」という記述は「アリティが2つ」を意味してます。)

&+/2と書けてしまう、ではなく・・・

elixirではそもそも「+」という関数が定義されておりました。
https://hexdocs.pm/elixir/Kernel.html#+/2
引数2つの「+」という関数を渡す際に &+/2 と表記するようです。

話が脱線してしまいましたが・・・

せっかくelixirで便利な関数が用意されているのだから、使用を禁止せずに素直に使った方が楽ですね(当然ですよねw)。

9
3
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
9
3