未経験文系初学者 Elixirを学ぶ 『プログラミングElixir』-第7章

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はElixirの教科書[『プログラミングElixir』](https://www.ohmsha.co.jp/book/9784274226373/)第7章を読んで、学んだことをまとめます。[^0]

#### 目次
[第4章へはこちらから](https://qiita.com/Alicesky2127/items/804c41110b0033fb7770)
[第5章へはこちらから](https://qiita.com/Alicesky2127/items/e12309be527d63644331)
[第6章へはこちらから](https://qiita.com/Alicesky2127/items/adccba8a61fe4ee2799b)
## 


## 実行環境
<dl>
  <dd>・Windows 11 Home(バージョン 21H2, OS ビルド 22000.613)</dd>
  <dd>・Ubuntu v18.04 ※WSL2環境下</dd>
  <dd>・Elixir v1.13.0 (compiled with Erlang/OTP 24) ※WSL2環境下</dd>
  <dd>・Phoenix v1.6.7 ※WSL2環境下</dd>
  <dd>・psql (PostgreSQL) 10.19 ※WSL2環境下</dd>
</dl>



以下私が詰まった箇所です。それ以外は本書か
[Elixir公式の学習ページ](https://elixir-lang.org/getting-started/basic-types.html#linked-lists)か、[Elixir School](https://elixirschool.com/ja/lessons/basics/basics)かで、学ぶことができます。


## 7.1　ヘッドとテイル  &  7.2　ヘッドとテイルによるリストの処理
リストはヘッドとそれ以外のテイル。テイルはリスト。再帰的になっている。


※変数の頭に_(アンダースコア)を入れると、その変数がモジュール内で一度も使用されていない場合の警告が出なくなる。


## 7.3　ヘッドとテイルを使ったリストの構築
,（カンマ）と｜（パイプ）記号1つ違うと意味が全く変わるので注意。

```elixir
# do: の後ろが　,　になっている場合
def add_1([]), do: []
def add_1([head | tail]),  do: [head+1 , add_1(tail)]


#例
def add_1([2, 4, 12])
   -> [2+1, add_1([4,12])]
     -> [3, [4+1, add_1([12])]]
       -> [3, [5, [12+1, add_1[]]]]
         -> [3, [5, [13, []]]]  #多重リスト（入れ子）になる
```

```elixir
# do: の後ろが　｜　になっている場合
def add_1([]), do: []
def add_1([head | tail]),  do: [head+1 | add_1(tail)]

#例
=def add_1([2, 4, 12])
   -> [2+1 | add_1([4, 12])
     -> [3 | [4+1 | add_1([12])]
       -> [3 | [5 | [12+1 | add_1[])]]
         -> [3 | [5 | [13 | []]]]
           -> [3] ++ [5] ++ [13] ++ [] # | はパターンマッチ以外においては ++ (リストの連結）の意味
             ->[3, 5, 13] #連結リストになる 
```


## 7.4　map関数の作成
map/2 関数(enumerable, fun)
リストと関数を引数とし、それぞれの要素に関数を適用して、新しいリストを返す。

```elixir
iex()> Enum.map([1, 2, 3, 4], fn(n) -> n + 1 end)
[2, 3, 4, 5]

iex()> Enum.map([1, 2, 3, 4], fn(n) -> n > 2 end)
[false, false, true, true]

iex()> Enum.map([1, 2, 3, 4], fn(n) -> n + 1 > 2 end)
[false, true, true, true]

iex()> Enum.map([1, 2, 3, 4], fn(n) -> n + 1 >= 2 end)
[true, true, true, true]

#略記するとこんな感じ↓　かっこやendタグの有無は慣れよう。
iex()> Enum.map [1,2,3,4], &(&1+1)
[2, 3, 4, 5]

iex()> Enum.map [1,2,3,4], &(&1) > 2
[false, false, true, true]

iex()> Enum.map [1,2,3,4], &(&1+1) > 2
[false, true, true, true]

iex()> Enum.map [1,2,3,4], &(&1+1) >= 2
[true, true, true, true]
```


## 7.5　リストを単一の値にまとめる
reduce/3 関数(enumerable, acc, fun)
初期値(acc)とリスト(enumerable)のヘッドの値に対して関数(fun)を実行し、実行結果を次の初期値とし、リストの次の値を取り出して、同様に関数を実行する。これをリストの末尾に到達するまで再帰的に繰り返す。

```elixir
iex()> Enum.reduce([1, 2, 3], 0, fn x, acc -> x + acc end)
6
```


## 7.6　より複雑なリストのパターン
リストのヘッド部は複数の条件を組みあわせることができる。

```elixir
  @doc """
  paramater swap.

  ## Examples
      iex> Practice.swap([])
      []
      iex> Practice.swap([2, 4, 6, 8])
      [4, 2, 8, 6]
  """

def swap([]), do: []
#空のリストが渡された時はそれをそのまま出力する。

def swap([a, b | tail]), do: ([b, a | swap(tail)])
#要素がa, b のペア、つまり、要素数が偶数個のリストが渡された時はそれをそのまま出力する。

def swap(_), do: raise "Can't swap a list with an odd number of elements" 
#それ以外、つまり、要素数が奇数個のリストが渡されたときは続くエラーメッセージを出力する。
#  ** (RuntimeError) Can't swap a list with an odd number of elementsというエラーメッセージが返ってくるのが期待値
```



## 7.7　実践Listモジュール & 7.8　リストと仲良くなろう
Elixirに標準組み込み済みのListモジュール。[公式ドキュメントはこちらから](https://hexdocs.pm/elixir/List.html)


#### flatten/1 (list)関数
平滑化 = 多重リストの入れ子をなくす。
```elixir
iex()> List.flatten([100, [200, 300, [400, 500], [600]]])
[100, 200, 300, 400, 500, 600]
```

#### replace_at/3 (list, index, value) 関数
リスト内のindexが条件と一致する場所にある要素を置き換える。
indexは0から始まる（つまり、要素の2番目はインデックス的には1）

```elixir
iex()> list = [1, 2, 3]
[1, 2, 3]

iex()> List.replace_at(list, 2, "buckle my shoe")
[1, 2, "buckle my shoe"]
```


#### keyfind/3 (list, key, position, default \\ nil)関数
positionにおけるkeyが条件が最初に一致したタプルを返す。
positionはタプル内におけるindexみたいなものか？

```elixir
iex()> kw = [{:name, "Dave"}, {:likes, "Programming"}, {:where, "Dallas", "TX"}]
[{:name, "Dave"}, {:likes, "Programming"}, {:where, "Dallas", "TX"}]

iex()> List.keyfind(kw, :likes, 0)
{:likes, "Programming"}

iex()> List.keyfind(kw, "Dallas", 1)
{:where, "Dallas", "TX"}

iex()> List.keyfind(kw, "TX", 2)
{:where, "Dallas", "TX"}

iex()> List.keyfind(kw, "Dallas", 2) #position2に存在するkeyが条件と一致しない
nil

```


<br>


# ～Elixirの国のご案内～
※Elixirって何ぞや？と思ったらこちらもどぞ。未来がぎゅっと詰まった、Elixirは今年で生まれて10周年です:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/7bf8f9f4f5f576e597f5



[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^9]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。


まずは気軽に話しかけてみてください。[^10]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian

[^0]:プログラミングが完全未経験ゆえ、「え？！そこからつまずく？！！」というお見苦しい箇所があるかと思いますが、私自身の記録のために残します。ご了承ください。

[^9]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。
[^10]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！