（初学者向け）すべてiexで簡単に、Enum.mapの動きをデバッグで見たい（dbg 編）~　dbgの解説付き　~

# はじめに

Enum.mapの処理手順をすべてiexで動かしながら、いかに手軽に確認できるかを考えました。
前回、
[（初学者向け）すべてiexで簡単に、Enum.mapの動きをデバッグで見たい（IO.inspect 編）](https://qiita.com/miwacchi/items/1b71d56d59724c394691)で書いたのですが、納得いくものではなったです。そこで、Elixirの偉大な先輩方にElixir1.14から`dbg`あるよと教えていただき、改めて作り直しました。

### 余談（ポエム）
`dbg`には、さまざま機能がありますが、具体的に何が出来るのか、身体で覚えていきたいと思います。
身体で覚えるとは、自ら手を動かしてハマって試し、「わかる」から「できる」になるという意味合いです。

身体で覚えるElixirシリーズ書いて行こうかな。確実に女性には嫌われるけど。lol

やりたいのは、「すべてiexで簡単に、Enum.mapの動きをデバッグで見たい」という事です。
普通に関数で書けば実現できるのは[前回](https://qiita.com/miwacchi/items/1b71d56d59724c394691)書きましたが、`iex`で楽してやりきりたい。そうしたら、今後気楽に`iex`でデバッグなんかもしながら、何でも分かった気になれるのではないかという淡い期待を元に書いています。

余談に付き合って頂きありがとうございます。

dbgとは、から書いていきます。

## dbg/2 とは

Elixir v1.14から、デバッグの強化のために`dbg/2`マクロが提供されました。

`dbg/2`は、BEAM VM上でイベントをトレースする機能を提供します。関数の呼び出しと戻り、例外の発生、メッセージの送受信、スポーン、終了、リンク、スケジューリング、ガベージコレクションなどの多くのイベント（ノードの集まり）の端から端までトレースすることができます。

IExの有無にかかわらず使用できるマクロです。
`dbg/2`はKernelモジュールに属し、どこからでも呼び出せます。
引数なしの`dbg()`で、現在束縛している変数の情報を表示します。
今回は、`dbg()`しか使わないので、詳細を知りたい方は公式を参考にしてください。
[hexdocs dbg はコチラ](https://hexdocs.pm/elixir/1.14.0-rc.0/Kernel.html#dbg/2)

※Elixir v1.14からしか利用できないので、ご注意ください。
[公式のElixir v1.14 releasedはこちら](https://elixir-lang.org/blog/2022/09/01/elixir-v1-14-0-released/)

## `dbg()`の基本的な使い方

例えば、以下のような関数を書きます。

`dbg()`は、実行されるタイミングで、その時点で束縛している変数の中身を出力してくれます。

また、`dbg()`を入れた関数を実行すると、リプライが`pry>`に変わり、`n`を入力する毎に、次の`dbg()`を実行してくれます。

言葉でいうと話が長く伝わりにくいので、実際に動かしてみてください。

実行結果は以下に貼り付けております。

```Elixir
$ iex
Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
iex> defmodule Ex3 do
iex>   def add(a) do
iex>     dbg()
iex>     r = a + 1
iex>     dbg()
iex>     r = r * 3
iex>     dbg()
iex>   end
iex> end
{:module, Ex3,
 <<70, 79, 82, 49, 0, 0, 18, 252, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 1, 3,
   0, 0, 0, 30, 10, 69, 108, 105, 120, 105, 114, 46, 69, 120, 51, 8, 95, 95,
   105, 110, 102, 111, 95, 95, 10, 97, 116, ...>>, {:add, 1}}
iex> Ex3.add(1)
Break reached: Ex3.add/1 (iex:3)
pry> n
binding() #=> [a: 1]

Break reached: Ex3.add/1 (iex:5)
pry> n
binding() #=> [a: 1, r: 2]

Break reached: Ex3.add/1 (iex:7)
pry> n
binding() #=> [a: 1, r: 6]

[a: 1, r: 6]

Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
```

こんな感じで`IO.inspect`と比べるとシンプルにデバッグできます。

でも、これって行単位の実行だから`Enum.map`の中の動きはトレース出来なくない？
と今更ながら気付くのです。この辺りは、Elixirの偉大な先輩方は自分で考える領域を残してくれています。結局自分で考えないと、記憶にも記録にも残らないのでとてもありがたいです。

もう一度、確認します。やりたかった事は何か？
「すべてiexで簡単に、Enum.mapの動きをデバッグで見たい」という事です。

まず、前回のおさらいです。

デバッグしたいのはこの処理です。
```Elixir
iex(2)> Enum.map([1, 2, 3], &(&1 + 1))
[2, 3, 4]
```

前回までは、`IO.inspect`を使って、このような形でインプット、アウトプットを出力し、処理状況が見えるようになりました。
```Elixir
iex(1)> Enum.map([1, 2, 3], &(IO.inspect(&1) + 1))
1
2
3
[2, 3, 4]
```

今回は、上記を改良していきます。
まず、何も考えないなら、`IO.inspect`を`dbg`に置き換えます。

```Elixir
iex(1)> Enum.map([1, 2, 3], &(dbg(&1) + 1))
Break reached: iex:1
pry(1)> n
x1 #=> 1

Break reached: iex:1
pry(1)> n
x1 #=> 2

Break reached: iex:1
pry(1)> n
x1 #=> 3

[2, 3, 4]

Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
```

`dbg`の出力結果を見ると、`&1`が`x1`として、中身が表示されました。
いい。これでいいんだけど、前に`dbg`入れたらどうなるのかな？

```Elixir
iex(3)> Enum.map([1, 2, 3], &(dbg(&1 + 1))
...(3)> )
Break reached: iex:3
pry(1)> n
x1 + 1 #=> 2

Break reached: iex:3
pry(1)> n
x1 + 1 #=> 3

Break reached: iex:3
pry(1)> n
x1 + 1 #=> 4

[2, 3, 4]

Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
```

計算過程`x1 + 1 #=> 2`が見えます。
でも、`x1 #=> 1`は消えました。

パイプで繋いだら見え方変わるかな？
ということで、やってみます。

```Elixir
iex(1)> Enum.map([1, 2, 3], &(&1 + 1 |> dbg()))
Break reached: iex:1
pry(1)> n
x1 + 1 #=> 2

Break reached: iex:1
pry(1)> n
x1 + 1 #=> 3

Break reached: iex:1
pry(1)> n
x1 + 1 #=> 4

[2, 3, 4]

Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
```

結果は同じです。

という事は、これまでの合わせ技で以下のように`dbg`を２つ書けばいいのではと考えました。

```Elixir
iex(1)> Enum.map([1, 2, 3], &dbg(dbg(&1) + 1))
Break reached: iex:1
pry(1)> n
Break reached: iex:1
pry(1)> n
x1 #=> 1

dbg(x1) + 1 #=> 2

Break reached: iex:1
pry(1)> n
Break reached: iex:1
pry(1)> n
x1 #=> 2

dbg(x1) + 1 #=> 3

Break reached: iex:1
pry(1)> n
Break reached: iex:1
pry(1)> n
x1 #=> 3

dbg(x1) + 1 #=> 4

[2, 3, 4]

Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
```

うん。理想的な結果だと思います。

しかし、課題は２つ残りました。

1. `dbg`を2回も書かないといけないという余分なコーディング
1. リプライがpry(1)>に変わった後、`n`を2回実行しないと一つ目の出力結果が表示されないという余分な操作。

2つ目については、偉大な先輩からアドバイスを頂き、`--no-pry`あるよと教えて頂きました。
必要な変数の束縛内容は出力されているのだから、止めてpry(のぞき見)する必要もないと気が付き、以下の通り`iex --no-pry`でスッキリ出力しました。

```Elixir
$ iex --no-pry
Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)

iex> Enum.map([1, 2, 3], &dbg(dbg(&1) + 1))
[iex:1: (file)]
x1 #=> 1

[iex:1: (file)]
dbg(x1) + 1 #=> 2

[iex:1: (file)]
x1 #=> 2

[iex:1: (file)]
dbg(x1) + 1 #=> 3

[iex:1: (file)]
x1 #=> 3

[iex:1: (file)]
dbg(x1) + 1 #=> 4

[2, 3, 4]
```

確かに、課題は残りましたが十分だと思います。

また、解決策が分かれば追記します！


もっといい方法があればご教授いただければ幸いです。