loading...
gumi TECH Blog

Elixir入門 04: パターンマッチング

gumitech profile image gumi TECH Updated on ・3 min read

本稿はElixir公式サイトの許諾を得て「Pattern matching」の解説にもとづき、加筆補正を加えてElixirの演算子による基本的なパターンマッチングについてご説明します。

マッチ演算子

演算子=/2は変数に値を代入するために用いることができます。

iex> x = 1
1
iex> x
1

=/2のElixirにおける呼び名はマッチ演算子です。左オペランドの値が右オペランドと合致(マッチ)するかを試します。マッチすればその値が返され、しないときはエラーになるのです。左オペランドが変数の場合には、右オペランドの値が代入されます。

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

右オペランドに未定義の変数があると、その名前のアリティ0の関数を探して呼び出そうとします。そして、見つからなければエラーになるのです。

iex> 1 = unknown
** (CompileError) iex:1: undefined function unknown/0

演算子によるパターンマッチング

複数のデータをもつリストやタプルにも、マッチ演算子=は使えます。

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

=演算子でリストの各要素を変数に取り出すこともできます。ただし、リストの長さもマッチしなければなりません。

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

|演算子を用いたパターンマッチングにより、ヘッドとテイルをふたつの変数に与えることもできます。ただし、関数hd/1tl/1と同じように、空のリストはマッチさせられません。

iex> [head | tail] = list
[1, 2, 3]
iex> [2, 3] = tail
[2, 3]
iex> [1] = head
** (MatchError) no match of right hand side value: 1
iex> 1 = head
1
iex> [h | t] = []
** (MatchError) no match of right hand side value: []

|演算子は、別のリストを後につなげるために用いることもできます。

iex> list = [1, 2, 3]
[1, 2, 3]
iex> [0 | list]
[0, 1, 2, 3]

タプルの要素も、マッチ演算子=で取り出せます。もちろん、要素の数はマッチしなければなりません。

iex> {a, b, c} = {:hello, "world", 2018}
{:hello, "world", 2018}
iex> a
:hello
iex> c
2018
iex(21)> {a, b} = {:hello, "world", 2018}
** (MatchError) no match of right hand side value: {:hello, "world", 2018}

両オペランドの型が異なると、マッチせずにエラーになります。

iex> {a, b, c} = [:hello, "world", 42]
** (MatchError) no match of right hand side value: [:hello, "world", 42]

左オペランドの要素の一部に値を与えることもできます。すると、その要素の値もマッチしなければならないのです。

iex> {:ok, result} = {:ok, 1}
{:ok, 1}
iex> result
1
iex> {:ok, result} = {:error, :oops}
** (MatchError) no match of right hand side value: {:error, :oops}

ピン演算子

=演算子の左オペランドが変数の場合、右オペランドの値が代入されます。けれど、左オペランドの変数にピン演算子^/1を添えると、右オペランドとのマッチが求められるのです。

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

^/1演算子はタプルにも使えます。左オペランドの^/1がついた変数は今もっている値に固定され、右オペランドの対応する要素がマッチしなければならなくなるのです。

iex> {x, y} = {2, 1}
{2, 1}
iex> {x, y} = {1, 2}
{1, 2}
iex> {^x, y} = {1, 3}
{1, 3}
iex> {^x, y} = {2, 2}
** (MatchError) no match of right hand side value: {2, 2}
iex> x
1
iex> y
3

=演算子の左オペランドのパターンに同じ変数が複数ある場合、それらはすべて同じパターンを参照します。そのため、同じ変数に異なる値は代入できません。けれど、同じ変数がふたつのとき、ひとつに^/1演算子を添えれば、パターンとして参照されるのは今の値です。したがって、^/1をつけた変数に対応する右オペランドの要素がその値とマッチすれば、もうひとつの変数に別の値を与えられます。

iex> {x, x} = {1, 1}
{1, 1}
iex> {x, x} = {1, 2}
** (MatchError) no match of right hand side value: {1, 2}
iex> x
1
iex> {^x, x} = {1, 2}
{1, 2}
iex> x
2

パターンの中の変数で値を問わない場合があるでしょう。そのときに用いるのがアンダースコア(_)です。

iex> [h | _] = [1, 2, 3]
[1, 2, 3]
iex> h
1

_は特別な変数です。値を取り出すことはできず、エラーになります。

iex> _
** (CompileError) iex:n: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions

Elixir入門もくじ

番外

Discussion

pic
Editor guide