9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 14

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

Last updated at Posted at 2024-12-13

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!"
9
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?