[Elixir in Action]Guard clauseの優先度

control flowの章の、 [Elixir in Action]Erlang/Elixirの再帰計算におけるnon-tail recursionとtail recursion 以外のことを。

以下のように、文字列バイナリも左辺/右辺のマッチングによって分けることができます。

iex > a = "hello world"
iex > "hello " <> b = a
iex > b
"world"

以下のように、連続したマッチングもできます。

iex(5)> a = ( b = 1 + 2 )
3
iex(6)> b
3

以下のように書いた場合、パターンマッチングでは上から順にマッチングを試みます。そのため a(other) が最も先頭にきたらそれがマッチングされます。

defmodule Sample do
  def a({:sample1, b}), do: something
  def a({:sample2, c}), do: something
  def a(other), do: something
end

Elixirでは、以下のようなGuard clauseによっても適用される関数を条件付けすることができます。この時、 when で使われる型には優先度が存在します。

defmodule Sample do
  def a(x) when x < 0, do: something
  def a(0), do: something
  def a(x) when x > 0, do: something
end

優先度は以下。

number < atom < reference < fun < port < pid < tuple < map < list < bitstring(binary)

つまり、上記の Sample.a/1 に対してatomの :not_a_number を適用した場合、

  def a(x) when x > 0, do: something

が適用されます。エラーはありません。
そのため、数字だけを受け付けるようにするために以下のように書きます。

defmodule Sample do
  def a(x) when is_number and x < 0, do: something
  def a(0), do: something
  def a(x) when is_number and x > 0, do: something
end

これで、 :not_a_number のようなものは FunctionClauseError がraiseされるようになります。

Cmprehensionsは、 for x &lt;- [list], do: {何か} で構成される。 into などの要素を使ったりすると、繰り返しをより簡潔にかけたりする。なるほど。

Streamの説明もありましたが、Stream、色々できそうですね。
File.stream! でStreamにした後にごにょごにょStreamで操作した最後にto_list などでlistにして処理をする、といった例が載ってましたが、イマドキぽい感じがします 🙂

Advertisements

One thought on “[Elixir in Action]Guard clauseの優先度

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s