MeWrite Docs

Elixir: BadArityError

Elixirで関数に渡す引数の数が間違っている場合のエラー

概要

Elixirで無名関数やキャプチャした関数を、定義されたアリティ(引数の数)と異なる数の引数で呼び出した場合に発生するエラーです。

エラーメッセージ

** (BadArityError) #Function<0.12345678/1 in MyModule.my_function/0> with arity 1 called with 2 arguments (1, 2)

原因

  1. 引数の数の不一致: 関数が期待する引数の数と渡した数が違う
  2. 関数キャプチャのアリティミス: &Module.function/n のnが間違っている
  3. 高階関数への渡し方: Enum.mapなどに渡す関数のアリティが違う

解決策

1. 無名関数のアリティを確認

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 悪い例
add = fn a, b -> a + b end
add.(1)  # BadArityError: arity 2 called with 1 argument

# 良い例
add.(1, 2)  # => 3

# または部分適用
add_one = fn a -> add.(a, 1) end
add_one.(5)  # => 6

2. Enum関数に渡す関数のアリティ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Enum.map は1引数の関数を期待
list = [1, 2, 3]

# 悪い例
Enum.map(list, fn a, b -> a + b end)  # BadArityError

# 良い例
Enum.map(list, fn x -> x * 2 end)
Enum.map(list, &(&1 * 2))

# reduce は2引数
Enum.reduce(list, 0, fn x, acc -> x + acc end)

3. 関数キャプチャのアリティ指定

1
2
3
4
5
6
7
8
9
# 悪い例:アリティが間違っている
Enum.map(list, &String.upcase/2)  # String.upcase/1 が正しい

# 良い例
Enum.map(["a", "b"], &String.upcase/1)

# 複数アリティがある場合は正しいものを選択
# String.split/1 と String.split/2 がある
Enum.map(["a,b", "c,d"], &String.split(&1, ","))

4. reduce_while のパターン

1
2
3
4
5
6
7
8
# reduce_while は {:cont, acc} または {:halt, acc} を返す
Enum.reduce_while(1..10, 0, fn x, acc ->
  if acc < 20 do
    {:cont, acc + x}
  else
    {:halt, acc}
  end
end)

5. Task.async で関数を渡す

1
2
3
4
5
6
7
8
9
# 悪い例
Task.async(fn a -> a + 1 end)  # 0引数の関数を期待

# 良い例
Task.async(fn -> expensive_operation() end)

# 引数を渡したい場合
value = 10
Task.async(fn -> process(value) end)

6. GenServerコールバックのアリティ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
defmodule MyServer do
  use GenServer

  # handle_call は3引数
  def handle_call(:get, _from, state) do
    {:reply, state, state}
  end

  # handle_cast は2引数
  def handle_cast({:set, value}, _state) do
    {:noreply, value}
  end
end

7. 関数情報を確認

1
2
3
4
5
6
# 関数のアリティを確認
fun = fn a, b -> a + b end
:erlang.fun_info(fun, :arity)  # {:arity, 2}

# またはFunction.info/2
Function.info(fun, :arity)  # {:arity, 2}

8. デフォルト引数でアリティを柔軟に

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
defmodule Math do
  # デフォルト引数により複数アリティを生成
  def add(a, b \\ 0, c \\ 0) do
    a + b + c
  end
end

# これらすべてが有効
Math.add(1)       # => 1
Math.add(1, 2)    # => 3
Math.add(1, 2, 3) # => 6

よくある間違い

  • Enum.each と Enum.map で期待されるアリティの混同
  • Stream関数のアリティ
  • with_index を使う場合のタプル引数
  • 関数を変数に束縛する際のキャプチャ忘れ

Elixir の他のエラー

最終更新: 2025-12-09