1. OverView
あー、これ、後で色々書き直すんだろうなぁ、と思いつつ、本日はパターンマッチでご機嫌を伺いたいとおもいます。
今回、「ピン演算子」と言うものが出てくるので、こいつをちゃんと読むと
「普通のプログラミング言語と同じ感覚」
で使える気がします…多分
本日のネタはこちらであります。
https://elixirschool.com/ja/lessons/basics/pattern_matching
2. まずは解説
2.1 マッチ演算子
さて、マッチ演算子ですね。
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 に2画’代入されてしまいます。
この例は、上の続きです。
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)
…こんな感じですね。
ここに「マップのキーや関数の節でのピン演算子がサポートされました」
と書いてあります。これで、マップからの要素の取り出しが便利になりますなぁ。
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 関数の節でのピン演算子の例
これ、非常に意味があるんですが…まだ関数を解説してないよw
例によって、匿名変数ですね。
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 1 iex(27)> 1 = x 1 |
^ | ピン演算子、マッチの際に、代入を行いません | |
リストのパターンマッチの例 | ||
タプルのパターンマッチの例 | iex(44)> {:ok, value} = {:ok, "Successful!"} {:ok, "Successful!"} iex(45)> value "Successful!" |