Elixir if～else／case／condの違い

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はif～else／case／condの違いについて学んだことをまとめます。
2024/9/15に開催したイベント[piyopiyo.ex #43：もくもく作業タイム](https://piyopiyoex.connpass.com/event/329872/)の成果です。

# 目的
if～else／case／condの違い、使いどころを理解する

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.17.0
Erlang v27.0

# if
コードの上から順に条件に当てはまるかを評価する
当てはまった場合。それ以降の条件式に当てはまるかどうかの評価はされない

## 例
```diff_elixir:iex
if String.valid?("Hello") do
  "Valid string!"
else
  "Invalid string."
end
```

```
"Valid string!"
```



## nilとfalseのみが偽とみなされる（truthyの場合）
Elixirではnilとfalseのみが偽とみなされます
```diff_elixir:iex
if "a string value" do
  "This is Truthy"
end
```

```
"This is Truthy"
```

## nilとfalseのみが偽とみなされる（nilの場合）
```diff_elixir:iex
if List.first([]) == nil do
  "this is an empty list"
else
  "this is not a empty list"
end 
```

```
"this is an empty list"
```

## nilとfalseのみが偽とみなされる（falseの場合）
```diff_elixir:iex
num = 15

if rem(num, 2) == 0 do
  "this is an even number"
else
  "this is an odd number"
end
```

```
"this is an odd number"
```

# case
1つの質問に対して答えを選ぶときに使う（=値に対する真偽を評価）
ガード節(=when句)に対応している
値がいずれにもマッチしない時の分岐を`_`で定義しないと、マッチしなかったとき`CaseClauseError`になる
## 例
```diff_elixir:iex
defmodule LeaningControlStructures do
   def exam_case(weather) do
    case weather do
     "sunny" -> "go outside"
     "rainy" -> "read books"
     _ -> "do some other things"
  end  
 end
end
```

```diff_elixir:iex
weather = "windy"
LeaningControlStructures.exam_case(weather)
```

```
"do some other things"
```

## case+ガード節
case文にガード節(=when句)を付けることで更に細かい条件分岐を付けることができます

### ガード節の条件にマッチするケース
```diff_elixir:iex
case {1, 2, 3} do
  {1, x, 3} when x > 0 ->
    "Will match"
  _ ->
    "Won't match"
end
```

```
"Will match"
```

### ガード節の条件にマッチしないケース
```diff_elixir:iex
case {1, 0, 3} do
  {1, x, 3} when x > 0 ->
    "Will match"
  _ ->
    "Won't match"
end

```

```
"Won't match"
```

## case+ピン演算子
caseはパターンマッチを使用しての分岐になるので、既存の変数に対してマッチさせたい場合にはピン演算子を使用します。

下記の例ではcase文の上から順にこのような内容の処理をしています
- ^pieはピン演算子があるので既存の変数 = 3.14とマッチしているかどうかのチェックを行う
- pieはピン演算子が無いので代入操作を行う

### (比較用)^pieとマッチしない分岐の場合
引数である"cherry pie"がpieに再束縛される
```diff_elixir:iex
pie = 3.14

case "cherry pie" do
  ^pie -> "Not so tasty"
   pie -> "I bet #{pie} is tasty"
end
```

```
"I bet cherry pie is tasty"
```

### (比較用)^pieとマッチする分岐の場合
```diff_elixir:iex
pie = 3.14

case 3.14 do
  ^pie -> "Not so tasty"
   pie -> "I bet #{pie} is tasty"
end
```

```
"Not so tasty"
```

# cond
複数の質問に対して「はい」があれば、その質問に基づいて行動する（=条件式に対する真偽を評価）
コードの上から順に条件に当てはまるかを評価して当てはまった場合分岐より下の条件式に当てはまるかどうかの評価はされない。
他の言語でいうところのelse ifにあたる。

## 例
`true`は他の言語でいうところのelse。
どの条件にも当てはまらなかったときに実行する処理を書いておく。
値がいずれにもマッチしない時の分岐を`true`で定義しないと、マッチしなかったとき`CaseClauseError`になる
```diff_elixir:iex
height = 150
age = 19

cond do
  height < 150 ->
    "You can't ride the roller coaster"
  age < 20 ->
    "You can't buy the alcohol"
  true -> 
    "You can ride the roller coaster and buy the alcohol"
end
```

```
"You can't buy the alcohol"
```

# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


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


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




[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！