2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Elixirでそげなことしよったちゃつまらんばい〜変数はイミュータブル!無名関数内での再代入は効かんとよ〜

Last updated at Posted at 2025-07-12

ChatGPT Image 2025年7月13日 09_13_07.png

はじめに

こんにちは!
大好評の「Elixirでそげなことしよったちゃつまらんばい」シリーズ記事です。
所属するfukuoka.ex にちなみ、福岡のとある地域でつかわれる方言をシリーズ名に冠しています。

📝 この記事の要約

  • Elixirの変数はイミュータブル(不変)である
  • 無名関数内で外部変数を再代入しても元の値は変わらない
  • 前の値を引き継ぐには Enum.reduce/3 を使う
  • 他言語の知識で書こうとすると「つまらんばい」になる実例を紹介

今回はElixirの変数はイミュータブルであるため、他のプログラミング言語の知識で書こうとしても、「つまらんばい」を紹介します。
私自身は、「Elixr実践入門」 という書籍 :book: の執筆にまでかかわらせていただくことができるまでにはなりましたが、学びはじめのころはこんな駄目なことをしていた思い出話でもあります。
日本全国あまねく地域の方に、伝わるとは思いますが、「そんなことしても駄目だぞ」ということです。

Elixirの変数はイミュータブル

まず、イミュータブル(不変)というのは、変数の値を変更できないことを意味します。例えば、以下のコードを見てください。

❌ 他言語の感覚で書いてしまう

a = 0

Enum.each(1..10, fn i ->
  a = a + i
end)

IO.puts(a) # 出力は0

このコードを実行すると、結果は0になります。
1〜10を足した松井秀喜選手の背番号である55ではありません。
なぜでしょうか?

なぜ出力が0になるのか?

無名関数の中でaを再代入しようとしていますが、Elixirではaはイミュータブルです。つまり、無名関数のスコープ内でaは常に初期値の0を参照します。これが「つまらんばい」な理由です。

どうすれば良いのか?

前の値を引き継ぐためには、Enum.reduce/3を使います。この関数は、リストの各要素に対して累積計算を行うのに役立ちます。

Enum.reduce/3の使い方

以下のコードを見てください。

⭕️ Enum.reduceを使って1から10までの合計を計算

total = Enum.reduce(1..10, 0, fn i, acc ->
  acc + i
end)

IO.puts(total) # 出力は55

このコードでは、Enum.reduce/3の第1引数が1から10の範囲、第2引数が初期値(0)、第3引数が無名関数です。この無名関数の引数は、現在の値iと、前回の計算結果accです。これにより、accは前の値を持ち続け、最終的に合計を計算することができます。

ちなみに、Enum.reduce/3 を専門家の間では「畳み込み」と呼びます。

つまずきやすいポイント

  • 無名関数のスコープ: 無名関数の中では、外部の変数を持ち込むことはできますが、変更することはできません。
  • イミュータブルの理解: イミュータブルの概念は他の言語(特にオブジェクト指向言語)でのミュータブルな変数の扱いとは異なるため、最初は混乱するかもしれません。

実践的な使用例

Elixirはデータ処理や並行処理に適しています。ここでは、リストの合計だけでなく、特定の条件に基づくフィルタリングと合計を行う例を示します。

# 偶数の合計を計算する
even_sum = Enum.reduce(1..10, 0, fn i, acc ->
  if rem(i, 2) == 0 do
    acc + i # 偶数の場合だけ加算
  else
    acc # 奇数はそのまま
  end
end)

IO.puts(even_sum) # 出力は30(2 + 4 + 6 + 8 + 10)

このコードでは、1から10までの数の中で偶数だけを合計しています。rem(i, 2) == 0で偶数を判定し、条件に合う場合だけaccに加算しています。

売上データの分析

上の例では実践的な使用例といいながら、「偶数の和」というまだ抽象的な例になってしまっていますが、表形式のようなデータがあったとしてある条件にあてはまるときだけ足すというようなことは現実でもよくありそうです。

実際のビジネスシーンでの応用例です。

# 売上データのリスト
sales_data = [
  %{product: "ノートPC", category: "electronics", amount: 120000, month: 3},
  %{product: "マウス", category: "electronics", amount: 3000, month: 3},
  %{product: "本", category: "books", amount: 1500, month: 2},
  %{product: "スマートフォン", category: "electronics", amount: 80000, month: 3},
  %{product: "雑誌", category: "books", amount: 800, month: 3}
]

# 3月の電子機器の売上合計を計算
march_electronics_total = Enum.reduce(sales_data, 0, fn item, acc ->
  if item.category == "electronics" and item.month == 3 do
    acc + item.amount
  else
    acc
  end
end)

IO.puts("3月の電子機器売上: #{march_electronics_total}円") # 203,000円

読者の皆さんへ

皆さんは、Elixirを学び始めた時にどんな「つまらんばい」を経験しましたか?
コメント欄で共有していただけると、他の初学者の方の参考になります!

まとめ

今回はElixirのイミュータブルな変数について学びました。イミュータブルの特性を理解することは、Elixirを効果的に使うための第一歩です。次に、Elixirの他の関数や並行処理の概念を学ぶことで、さらに深い理解を得ることができます。

次のステップとして、Enum.map/2Enum.filter/2などの他の関数を試してみてください。それでは、楽しいElixirライフを!

ChatGPT Image 2025年7月12日 10_22_33.png

自称・闘魂プログラマー。主な著書に『Elixir実戦入門』。私のAIは一味違う。Artificial Intelligenceではなく、Antonio Inokiさんの方のAI、つまり猪木さん。闘魂と共に、世界恒久平和の実現を目指してコードを書く。

2
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?