Elixir 関数パターンマッチ+ガード節

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回は関数パターンマッチ+ガード節でさらに条件を絞り込む方法について学んだことをまとめます。

# 目次
1.[パターンマッチと関数パターンマッチ](https://qiita.com/Alicesky2127/items/c5d49496a89c3a91e815)
2.関数パターンマッチ+ガード節(本記事)

# 目的
関数パターンマッチ+ガード節でさらに条件を絞り込む方法を理解する

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

# 今回やりたいこと
前回は下記2つが条件分岐できていませんでした。

- 引数のリストの要素数が2以上であるとき
- 引数がそもそもリストではないとき

そこで、ガード節を使ってこの部分をさらに細かく条件分岐したいと思います

## 前提
前回作成したElixirプロジェクトをそのまま使います
```shell:bash
mix new func_matching
cd func_matching
```

開始時点でのテストモジュールは以下の通りです
```diff_elixir:test/func_matching_test.exs
describe "check list elements" do
  test "when list is []" do
    assert FuncMatching.checkelems([]) == "空のリストです"
  end

  test "when list has only one element" do
    assert FuncMatching.checkelems([5]) == "リストの要素数は1です"
  end

  test "other pattern" do
    assert FuncMatching.checkelems([1, 2, 3]) == "リストの要素数は2以上であるか、そもそもリストではありません"
  end

  test "when argument is not a list" do
    assert FuncMatching.checkelems("hoge") == "リストの要素数は2以上であるか、そもそもリストではありません"
  end
end
```

開始時点での実装は以下の通りです。
`countelems(_)`は、
- 引数のリストの要素数が2以上であるとき
- 引数がそもそもリストではないとき

を区別できていません。

```diff_elixir:lib/func_matching.ex
defmodule FuncMatching do
  def countelems([]) do
    "空のリストです"
  end

  def countelems([_]) do
    "リストの要素数は1です"
  end

  def countelems(_) do # 上記のいずれにもマッチしなかった場合
    "リストの要素数は2以上であるか、そもそもリストではありません"
  end
end
```

## テストの修正
```diff_elixir:test/func_matching_test.exs
describe "check list elements" do
    test "when list is []" do
      assert FuncMatching.checkelems([]) == "空のリストです"
    end

    test "when list has only one element" do
      assert FuncMatching.checkelems([5]) == "リストの要素数は1です"
    end

-   test "other pattern" do
-     assert FuncMatching.checkelems([1, 2, 3]) == "リストの要素数は2以上であるか、そもそもリストではありません"
-   end

+   test "when list has more than two elements" do
+     assert FuncMatching.checkelems([1, 2, 3]) == "リストの要素数は2以上です"
+   end

    test "when argument is not a list" do
-     assert FuncMatching.checkelems("hoge") == "リストの要素数は2以上であるか、そもそもリストではありません"
+     assert FuncMatching.checkelems("hoge") == "リストではありません"
    end
  end
```


## 関数の修正
ガード節(when句)を使用して条件分岐をさらに細かくします
```diff_elixir:lib/func_matching.ex
 defmodule FuncMatching do
   def countelems([]) do
     "空のリストです"
   end
 
   def countelems([_]) do
     "リストの要素数は1です"
   end
 
-  def countelems(_) do # 上記のいずれにもマッチしなかった場合
-    "リストの要素数は2以上であるか、そもそもリストではありません"
-  end
+  def checkelems(list) when is_list(list) do
+   "リストの要素数は2以上です"
+  end
+
+  def checkelems(_) do # 上記のいずれにもマッチしなかった場合
+    "リストではありません"
+  end
  end
```



# ～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コミュニティはいろんな形で活動中！