Elixirのチートシートを作ろう #8 パターンマッチのプロローグ うん、ただの代入じゃないややこしい話



# 1. OverView

あー、これ、後で色々書き直すんだろうなぁ、と思いつつ、本日はパターンマッチでご機嫌を伺いたいとおもいます。

今回、「ピン演算子」と言うものが出てくるので、こいつをちゃんと読むと
「普通のプログラミング言語と同じ感覚」
で使える気がします…多分

本日のネタはこちらであります。
https://elixirschool.com/ja/lessons/basics/pattern_matching

# 2. まずは解説
## 2.1 マッチ演算子

さて、マッチ演算子ですね。

https://elixirschool.com/ja/lessons/basics/pattern_matching#%E3%83%9E%E3%83%83%E3%83%81%E6%BC%94%E7%AE%97%E5%AD%90-0

```
Elixirでは、 = 演算子は実際には代数学での等号に値するマッチ演算子です。
このマッチ演算子を通して値を代入し、その後マッチさせることができます。
マッチングに成功すると方程式の結果を返します。
```

普通のプログラミング言語に「代入」と、マッチがセットになっております。

```
iex(26)> x = 1
1
iex(27)> 1 = x
1
```
xに1を代入、その後、1=xでマッチするか確認しております。
左辺が1なのに注意してください。。。

マッチしないと、エラーが出ます。
```
iex(28)> 2 = x
** (MatchError) no match of right hand side value: 1
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:28: (file)
iex(28)>
```

さて、先ほど「左辺が1なのに注意してください。。。」と書きましたが、この例を見ていただけると、
何を言ってるかわかっていただけると思います。

これ、xに1が代入されて増して…こいつの続きでこう書いちゃうと、x に２画’代入されてしまいます。
この例は、上の続きです。
```
iex(28)> x = 2　-> これで、xが1から2になっております。
2
iex(29)> 1 = x -> これがエラーになる
** (MatchError) no match of right hand side value: 2
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:29: (file)
iex(29)> 2 = x
2
iex(30
```

これは困った、と言うわけで、次のピン演算子となります。

## 2.2 ピン演算子

代入を行わない、ピン演算子があります。

```
iex(30)> x = 1
1
iex(31)> ^x = 2
** (MatchError) no match of right hand side value: 2
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:31: (file)
iex(31)> ^x = 1
1
```

## 2.3 別のコレクションでのパターンマッチ例

パターンマッチやピン演算子の具体的な使い方は、こいつの使い方は、後の方で出てくると思うので、本日は、別のコレクションでのパターンマッチを
列挙して終わりにしましょうか。

### 2.3.1 リストのパターンマッチの例

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

ピン演算子でもやってみましょうか。
```
iex(34)> ^list = [1,2,3]
[1, 2, 3]
iex(35)> ^list = [1,2,4]
** (MatchError) no match of right hand side value: [1, 2, 4]
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:35: (file)
```

listの一部を、代入で取り出してますね。
以下で、tailに、何が入るかを確認してみましょう。

```
iex(35)> [ 1 | tail ] = list
[1, 2, 3]
iex(36)> tail
[2, 3] -> tailには、2,3が代入されている。
iex(37)> hd( list )
1
iex(38)> tl( list )
[2, 3]
```

当然、マッチングの失敗もあります
```
iex(1)>  list = [1,2,3]
[1, 2, 3]
iex(2)> [ 1 | tail ] = list
[1, 2, 3]
iex(3)> tail
[2, 3]
iex(4)> [2|_] = list
** (MatchError) no match of right hand side value: [1, 2, 3]
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:4: (file)
iex(4)> [2|_] = tail
[2, 3]
iex(5)>
```

### 2.3.2 タプルのパターンマッチの例

タプルは、関数の結果引き渡しなんかにも使うので、こういう使い方が出来ます。
まずは、例から見ましょうか

```
iex(44)> {:ok, value} = {:ok, "Successful!"}
{:ok, "Successful!"}
iex(45)> value
"Successful!"
```

…これ、関数の戻り値（タプル）を確認、成功した場合だけvalueを取り出しております。
エラーの際の動作を確認しておきましょうか？
```
iex(46)> {:ok, value} = {:error}
** (MatchError) no match of right hand side value: {:error}
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:46: (file)
iex(46)> {:ok, value} = {:error, "mokemoke"}
** (MatchError) no match of right hand side value: {:error, "mokemoke"}
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:46: (file)
```
…こんな感じですね。

https://elixirschool.com/ja/lessons/basics/pattern_matching#%E3%83%94%E3%83%B3%E6%BC%94%E7%AE%97%E5%AD%90-1

ここに「マップのキーや関数の節でのピン演算子がサポートされました」
と書いてあります。これで、マップからの要素の取り出しが便利になりますなぁ。

```
iex(46)> key = "hello"
"hello"
iex(47)> %{^key => value} = %{"hello" => "world"}
%{"hello" => "world"}
iex(7)> value
"world"
```
なお、該当するキーが無ければ、以下の様に、エラーとなります

```
iex(49)> %{^key => value} = %{:hello => "world"}
** (MatchError) no match of right hand side value: %{hello: "world"}
    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6
    iex:49: (file)
```

### 2.3.2 関数の節でのピン演算子の例

これ、非常に意味があるんですが…まだ関数を解説してないよｗ
例によって、匿名変数ですね。
```
iex(49)> greeting = "Hello"
"Hello"
iex(50)> greet = fn
...(50)>   (^greeting, name) -> "Hi #{name}"
...(50)>   (greeting, name) -> "#{greeting}, #{name}"
...(50)> end
```

上の例だと、greetを匿名関数にbindしております。
上の例だけで、二つの関数を定義してますね。
```
...(50)>   (^greeting, name) -> "Hi #{name}"
...(50)>   (greeting, name) -> "#{greeting}, #{name}"
```

引数、greetingと、nameをとるのですが、
greetingの値で、どちらにmatchするかが変わります。

```
iex(51)> greet.("Hello", "Sean")
"Hi Sean"
```

^greetingは"Hello"とマッチするので、"Hi #{name}"が返ります。
次の行とは、マッチしません。

```
iex(52)> greet.("Hello", "Sean") |> dbg()
[iex:52: (file)]
greet.("Hello", "Sean") #=> "Hi Sean"

"Hi Sean"
iex(53)> greet.("Morning", "Sean") |> dbg()　-> マッチングしないですね。
[iex:53: (file)]
```

以上、パターンマッチングの紹介でした。
もっと深くやらんとダメですねぇ。これは。

## 3. 本日のチートシート！
  |演算子|説明|例|
  |:--------|:----------------------------------------|:------------------------------------------------------------------|
  |=|マッチ演算子、マッチ演算子を通して値を代入し、その後マッチさせることができます|iex(26)> x = 1<br>1<br>iex(27)> 1 = x<br>1|
　|^|ピン演算子、マッチの際に、代入を行いません|iex(31)> ^x = 2<br>** (MatchError) no match of right hand side value: 2<br>    (stdlib 5.0.2) erl_eval.erl:498: :erl_eval.expr/6<br>    iex:31: (file)<br>iex(31)> ^x = 1<br>1<br>|
　||リストのパターンマッチの例|iex(32)> list = [1,2,3]<br>[1, 2, 3]<br>iex(33)> [1,2,3] = list<br>[1, 2, 3]<br>|
  ||タプルのパターンマッチの例|iex(44)> {:ok, value} = {:ok, "Successful!"}<br>{:ok, "Successful!"}<br>iex(45)> value<br>"Successful!"|