Elixirのチートシートを作ろう #10 制御構造その２

# 1. OverView

さて、二日に分けた制御構造の続き。完走するなら、あと13日分かー。


# 2. まずは解説
## 2.1 cond

さて、 Elixir Schoolの解説を見てみましょう。
https://elixirschool.com/ja/lessons/basics/control_structures#cond-2

値ではなく、条件をマッチさせる必要がある時には、 cond/1 を使うことができます。これは他の言語でいうところの else if や elsif のようなものです:

まずはサンプルの実行
```
iex(14)> cond do
...(14)>   2 + 2 == 5 ->
...(14)>     "This will not be true"
...(14)>   2 * 2 == 3 ->
...(14)>     "Nor this"
...(14)>   1 + 1 == 2 ->
...(14)>     "But this will" <-こいつだけが実行されますね。
...(14)> end
"But this will"
```

次
```
iex(15)> cond do
...(15)>   7 + 1 == 0 -> "Incorrect"
...(15)>   true -> "Catch all" <-こいつが実行されております
...(15)> end
"Catch all
```
```
iex(19)> a = 1
1
iex(20)> b = 3
3
iex(21)> a + b
4
iex(22)>
nil
iex(23)> cond do
...(23)>   a + b == 2 -> "OK"
...(23)>   true -> "Catch all"
...(23)> end
"Catch all"
```

Else ifと言っているので、以下の様に

```
iex(31)> cond do
...(31)>   a + b == 2 -> "OK,2"
...(31)>   a + b == 4 -> "OK,4" -->ここがtrueになる
...(31)>   true -> "Catch all"　--> ここは評価されない。
...(31)> end
"OK,4"
```

先頭からやって、trueになると抜けるんですね。これ。


## 2.2 with

### 2.2.1 withの説明

うん、これの為にdayを分けた。
https://elixirschool.com/ja/lessons/basics/control_structures#with-3

「特殊形式の with/1 はネストされた case/2 文を使うような時やきれいにパイプできない状況に便利です。 with/1 式はキーワード, ジェネレータ, そして式から成り立っています」

後半はわかるが…文法を調べないとさっぱりわからないな。
```
with
    pattern1 <- expression1,
    pattern2 <- expression2, ...,
do:
    result_expression
```

これ、withの後の条件が満たされた場合、「すべてが条件式を満たしたら」 do:以下のresult_expressionが実行されるらしい。

では、サンプル…理解の前にElixir Schoolの文章を読んでみましょう。

「ジェネレータについてはリスト内包表記のレッスンでより詳しく述べますが、今は <- の右側と左側を比べるのにパターンマッチが使われることを知っておくだけでよいです。」

<-の右側と左側を比べるのに、パターンマッチ、つまり、これ、関数が実行されるんですね。
なので、例は…
```
user = %{first: "Sean", last: "Callan"}
```

これとmatchする
```
with {:ok, first} <- Map.fetch(user, :first),
     {:ok, last} <- Map.fetch(user, :last),
     do: last <> ", " <> first
```

1行ずつ見ていくと、
Map.fetch(user, :first)　　こいつの結果が{:ok, "Sean"}
Map.fetch(user, :last),　　こいつの結果が{:ok, "Callan"}

それぞれの行がマッチするので、do:以降のresult_expressionが実行されます。

今回はresult_expressionは、以下ですね。
このサンプル、実に味があるなと思うのが、結果。
```
     do: last <> ", " <> first
"Callan, Sean"
```

結果が意味深でして。
上にも書いたとおり、「今は <- の右側と左側を比べるのにパターンマッチが使われることを知っておくだけでよいです。」の通りでして。
上の二つのパターンマッチが行われているので、last, firstに値がbindされてます。

### 2.2.2 with/1でelseが使えます
次のサンプル
Elixir 1.3からは with/1 で else を使えます:
```
import Integer
m = %{a: 1, c: 3}
a =
  with {:ok, number} <- Map.fetch(m, :a),
    true <- is_even(number)
  do
      IO.puts "#{number} divided by 2 is #{div(number, 2)}"
      :even
  else
    :error ->
      IO.puts("We don't have this item in map")
      :error
    _ ->
      IO.puts("It is odd")
      :odd
  end
```
実行結果が
```
It is odd
```

さて、細かく説明（と言うか、俺の理解が…）
```
 {:ok, number} <- Map.fetch(m, :a)  mのmapに入っているa:を取り出して、評価しております。
  is_even(number) numberが偶数か奇数か判定
```
これ、先ほども話した通り「今は <- の右側と左側を比べるのにパターンマッチが使われることを知っておくだけでよいです」ですね。
この両方が実行されます。
elseにて、この条件に当てはまらない

elseで二つのケースのエラーハンドリングをしています。
```
    :error ->
      IO.puts("We don't have this item in map")
      :error
    _ ->
      IO.puts("It is odd")
      :odd
```
まずは、:error。これは、Map.fetch(m, :a) が失敗した場合ですね。
次、_で、Map.fetch(m, :a)は成功したが、is_even(number)がfalseだった場合となります。

では、実行結果を張っておきます
```
m = %{a: 2, c: 3}
2 divided by 2 is 1
:even

m = %{q: 2, c: 3}
We don't have this item in map
:error
```

# 3. 本日のチートシート！
  |制御構造の名|説明|例|
  |:--------|:----------------------------------------|:------------------------------------------------------------------|
  |cond|値ではなく、条件をマッチさせる|cond do<br>   7 + 1 == 0 -> "Incorrect"<br>  true -> "Catch all"<br>end<br>"Catch all"<br>|
  |with|withで指定された複数のパターンマッチを行い、trueであればdo以下を実行する|with {:ok, first} <- Map.fetch(user, :first),<br>     {:ok, last} <- Map.fetch(user, :last),<br>     do: last <> ", " <> first<br>"Callan, Sean"|


# 4. 本日の課題.…

僕の宿題をまとめておきます。

## 4.1 Elixir Schoolのwithのリファクタリング例を、ちゃんと説明しよう