猪木イズムで挑むElixirの再帰関数

```elixir
defmodule FightingSpirit do
  def shout do
    IO.puts "元氣ですかーーーッ！！！"
    IO.puts "元氣があればなんでもできる！"
    IO.puts "闘魂とは己に打ち克つこと。"
    IO.puts "そして闘いを通じて己の魂を磨いていく"
    IO.puts "ことだと思います。"
  end
end

FightingSpirit.shout()
```

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>  
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>  
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>  
<b><font color="red">$\huge{ことだと思います。}$</font></b>


![DALL·E 2024-11-02 15.45.01 - .jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/908babbd-97f0-64bb-4d18-cbcfca77b3cf.jpeg)


---

# はじめに

[Elixir](https://elixir-lang.org/)の醍醐味である再帰関数。これはまさに猪木イズムの「道」のごとく、深く探求する価値があります。再帰関数を理解し使いこなすことで、Elixirのコードに闘魂を注ぎ込むことができます。本記事では、再帰関数の基本から応用までを、猪木さんの名言とともに解説します。

# 1. 再帰関数とは

**「この道を行けばどうなるものか、危ぶむなかれ。危ぶめば道はなし。」**

再帰関数の概念を恐れずに、一歩踏み出しましょう。
**闘魂をもって、自らの道を切り開く勇気を持とう！**

再帰関数とは、自身を呼び出すことで繰り返し処理を行う関数のことです。





## 基本的な再帰関数の例

基本的な再帰関数の例を示します。

### 例: 階乗の計算

階乗の計算例です。

```elixir
defmodule Factorial do
  def calculate(0), do: 1
  def calculate(n) when n > 0 do
    n * calculate(n - 1)
  end
end

Factorial.calculate(5)  #  => 120
```

### 解説

- `calculate/1`関数は、`n`が0の場合は1を返し、それ以外の場合は`n * calculate(n - 1)`を計算します。
- これにより、5の階乗は`5 * 4 * 3 * 2 * 1 = 120`となります。

# 2. パターンマッチングとの組み合わせ

**「出る前に負けること考える馬鹿いるかよ！」**

複雑な処理も恐れずに挑戦しましょう。
**挑戦することが、真の成長をもたらすのです！**

再帰関数とパターンマッチングを組み合わせることで、より強力な処理が可能になります。



複雑な処理も恐れずに挑戦しましょう。

## 例: リスト内の特定の要素をカウント

リスト内の特定の要素をカウントする例です。

```elixir
defmodule CountItem do
  def count([], _item), do: 0
  def count([item | tail], item), do: 1 + count(tail, item)
  def count([_ | tail], item), do: count(tail, item)
end

CountItem.count([:red, :blue, :red, :green, :red], :red)  #  => 3
```

### 解説

- リストの先頭要素とカウントしたい`item`が一致する場合、1を加算します。
- 一致しない場合はそのまま再帰を続けます。

# 3. 再帰関数の応用

再帰関数を使ってさまざまなアルゴリズムを実装できます。

## 例: フィボナッチ数列

フィボナッチ数列を再帰で書いてみます。

```elixir
defmodule Fibonacci do
  def calc(0), do: 0
  def calc(1), do: 1
  def calc(n) when n > 1 do
    calc(n - 1) + calc(n - 2)
  end
end

Fibonacci.calc(10)  #  => 55
```

### 解説

- フィボナッチ数列を再帰的に計算しています。
- しかし、この方法は同じ計算を何度も行うため、効率的ではありません。
- `Fibonacci.calc(50)`くらいでなかなか計算が終わりません。

### 改善策

同じ計算を繰り返さないように、こんなやり方もあります。

```elixir
defmodule Fibonacci do
  def calc(n), do: fib(n, 0, 1)

  defp fib(0, a, _), do: a
  defp fib(n, a, b), do: fib(n - 1, b, a + b)
end

Fibonacci.calc(50)  # => 12586269025
```

この実装では、計算済みの値を再利用することで、無駄な計算を省き効率的に結果を得ています。

50番目も即座に評価結果を得られます！
同じ道を何度も辿ることなく、一歩一歩確実に進むことで、大いなる目標に速やかに到達できるのです。

了解しました！では、もっと短いケーススタディの例を以下に示します。

---

## ケーススタディ: フィボナッチ数列の計算

フィボナッチ数列は、再帰関数を使って簡単に計算できますが、効率性を考慮することが重要です。以下は、メモ化を使用したフィボナッチ数列の計算例です。

```elixir
defmodule Fibonacci do
  def calc(n), do: fib(n, %{})

  defp fib(0, memo), do: {0, memo}
  defp fib(1, memo), do: {1, memo}
  defp fib(n, memo) do
    case Map.get(memo, n) do
      nil -> compute_fib(n, memo)
      result -> {result, memo}
    end
  end

  defp compute_fib(n, memo) do
    {a, memo} = fib(n - 1, memo)
    {b, memo} = fib(n - 2, memo)
    result = a + b
    new_memo = Map.put(memo, n, result)
    {result, new_memo}
  end
end

{result, _} = Fibonacci.calc(50)  # => resultには12586269025が束縛されます
```

このように、再帰を用いて計算したフィボナッチ数列も、メモ化を活用することで効率的に結果を得ることができます。

# どうやって実行するんだー！？　バカヤローって方へ

GitHubのアカウントをお持ちの方へお手軽な方法を示しておきます。
[PhoenixアプリケーションをGitHub Codespaces上で開発する方法](https://qiita.com/torifukukaiou/items/5dd716cb04db9b46bc92)で紹介した[GitHub Codespaces](https://github.co.jp/features/codespaces)を使うという方法です。

https://qiita.com/torifukukaiou/items/5dd716cb04db9b46bc92

記事中で紹介している[phx_devcontainer](https://github.com/TORIFUKUKaiou/phx_devcontainer)を使うと、ElixirがインストールされたUbuntuコンテナが立ち上がるので、Ubuntu上で直接開発をしているかのように操作ができます。`iex`コマンドでREPL(Read-Eval-Print Loop)が立ち上がるのでこの記事のコード例をぜひ試してください。

![スクリーンショット 2024-11-02 14.11.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/303ee996-0b65-30c9-9b75-08d297b96f7a.png)



# 4. まとめ

再帰関数はElixirの強力なツールであり、効率的なアルゴリズムを実装する鍵となります。
再帰関数を使いこなすことでコードに闘魂を込めることができます。猪木さんの名言に励まされながら、恐れずに挑戦し続けましょう。

**「道は自分で切り開くもの。再帰の道を極め、さらなる高みへと進もう！」**

# 5. 次への一歩

「**挑戦こそが未来を切り開く原動力である。**」

- 再帰関数を使って独自のアルゴリズムを実装してみましょう。
- パターンマッチングを駆使して、複雑なデータ構造を操作する再帰関数を書いてみてください。
- メモ化や他の最適化手法を学び、効率的な再帰関数を目指しましょう。