読者です 読者をやめる 読者になる 読者になる

Programming Elixir - パターンマッチング

Elixir プログラミング

パターンマッチング

  • パターンマッチングは変数に値を束縛する
  • マッチングで構造化されたデータを操作する
  • アンダースコアはパターンマッチングを無視する
iex(1)> a = 1
1
iex(2)> a + 3
4

aに1を代入して、その後3を加算したので結果が4になる、というのが普通だと思いますが、Elixirではこれは間違いです。=は代入ではなくマッチ演算子です。

マッチ演算子の左辺は、右辺の値になろうとします。もし右辺になれる場合にはその値を変数に束縛します。先ほどの例だと変数aが1になれるかどうかが判定されます。判定された結果、変数aは1に束縛されたという事です。

iex(1)> a = 1
1
iex(2)> 1 = a
1
iex(3)> 2 = a
** (MatchError) no match of right hand side value: 1

続いての例だと、1行目のa = 1でaは1に束縛されます。2行目は左辺と右辺が一致しているのでマッチ成功です (ただし束縛は無し)。3行目、左辺が右辺になろうとする習性がありますが、数値リテラルである2は、既に1に束縛されているaとはどうあっても一致できないのでMatchErrorが出力されます。

複雑なマッチ

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

いきなりリストです。リストは[]で囲み、カンマ区切りで記述します。

iex(1)> list = [100, 200, 300]
[100, 200, 300]
iex(2)> [a, b, c] = list
[100, 200, 300]
iex(3)> a
100
iex(4)> b
200
iex(5)> c
300

2行目で、リスト内の要素に対してa、b、cの各変数をパターンマッチし、束縛を行っています。

iex(1)> list = [1, 2, [3, 4, 5]]
[1, 2, [3, 4, 5]]
iex(2)> [a, b, c] = list
[1, 2, [3, 4, 5]]
iex(3)> a
1
iex(4)> b
2
iex(5)> c
[3, 4, 5]

ここまでの例で、パターンマッチングで数値やリストそのものに変数を束縛出来ることが分かりました。

アンダースコア

iex(1)> [1, _, _] = [1, 2, 3]
[1, 2, 3]
iex(2)> [1, _, _] = [1, "hoge", "fuga"]
[1, "hoge", "fuga"]

変数を束縛する必要が無い時、ワイルドカードとして使えます。

1つのマッチで束縛は1回

iex(1)> [a, a] = [1, 1]
[1, 1]
iex(2)> a
1
iex(3)> [a, a] = [1, 2]
** (MatchError) no match of right hand side value: [1, 2]

3行目、最初のaは1に束縛されますが、1度のマッチでは1回しか束縛がされないので、2個目のaのマッチが失敗します。

再束縛とその抑止

iex(1)> a = 1
1
iex(2)> a = 2
2

一度束縛した変数に対して、別の値を束縛し直す事ができます。 パターンマッチで束縛をさせない場合には^を変数の頭に付けます。

iex(1)> a = 1
1
iex(2)> ^a = 2
** (MatchError) no match of right hand side value: 2

iex(2)> a = 2
2

2行目でマッチに失敗しています。再束縛を行わず、先に束縛された1を用いてパターンマッチを試みた結果ですね。