[Elixir] guard構文徹底攻略

# やりたいこと

パターンマッチをバキバキに仕上げてくれるのが、`when`から始まるguard構文。標準で様々な演算子と関数が使えるようになっている。やや量が多いので、しっかりと使いこなせるようにするため汎用性の高そうなguardを一通り書いてみた。

## 演算子

演算子は以下のものが利用可能。詳細は[こちら](http://elixir-ja.sena-net.works/getting_started/5.html)参照

```
比較演算子(==，!=，===，!==，>，<，<=，>=)
論理演算子(and，or)と否定演算子(not，!)
算術演算子(+，-，*，/)
左側がリテラルの場合の<>と++
in演算子
```

## チェック関数

で、以下がメインコンテンツ。標準ライブラリから様々なチェック関数が提供されているので、使いそうなものを片っ端から使ってみた。また、いくつかElixirの変数型仕様によるハマりどころもあったので、メモ書き程度だが付記しておく。

```test/guard_test.exs
defmodule Demo.GuardTest do
  use Demo.ConnCase

  def this_is(x) when is_nil(x), do: "This is nil"
  def this_is(x) when is_atom(x), do: "This is Atom"
  def this_is(x) when is_binary(x), do: "This is Binary"
  def this_is(x) when is_bitstring(x), do: "This is Bitstring"
  def this_is(x) when is_boolean(x), do: "This is Boolean"
  def this_is(x) when is_integer(x), do: "This is Integer"
  def this_is(x) when is_float(x), do: "This is Float"
  def this_is(x) when is_list(x), do: "This is List"
  def this_is(x) when is_tuple(x) and tuple_size(x) == 2, do: "This is Tuple with two elements"
  def this_is(x) when is_tuple(x), do: "This is Tuple"
  def this_is(x) when is_map(x), do: "This is Map"
  def this_is(x) when is_function(x, 2), do: "This is Function with two arguments"
  def this_is(x) when is_function(x), do: "This is Function"

  def this_is_number(x) when is_number(x), do: "This is Number; can be both Integer/Float"
  def this_is_actually_boolean(x) when is_boolean(x), do: "This is Actually Boolean"

  def they_are(x, y) when is_atom(x) and is_binary(y), do: "They are Atom and Binary"

  test "nil in guards", _ do
    assert this_is(nil) == "This is nil"
  end

  test "Atoms in guards", _ do
    assert this_is(:foobar) == "This is Atom"
    assert this_is(false) == "This is Atom"
  end

  test "Strings in guards", _ do
    assert this_is("foobar") == "This is Binary"
    assert this_is(<<102>>) == "This is Binary"
    assert this_is(<< 1 :: size(1)>>) == "This is Bitstring"
    assert this_is('foobar') == "This is List"
  end

  test "Booleans in guards", _ do
    assert this_is(true) != "This is Boolean" # this matches is_atom so the function returns "This is Atom"
    assert this_is_actually_boolean(true) == "This is Actually Boolean"
    assert this_is_actually_boolean(:true) == "This is Actually Boolean" # this matches is_boolean too because true/false are technically atom
  end

  test "Numbers in guards", _ do
    assert this_is(1) == "This is Integer"
    assert this_is(0b10) == "This is Integer" # Binary
    assert this_is(0o77) == "This is Integer" # Octal
    assert this_is(0x1F) == "This is Integer" # Hexadecimal
    assert this_is(0.1) == "This is Float"
    assert this_is_number(101) == "This is Number; can be both Integer/Float"
    assert this_is_number(1.1) == "This is Number; can be both Integer/Float"
  end

  test "Lists in guards", _ do
    assert this_is([:ok, "foo", 0]) == "This is List"
    assert this_is('foobar') == "This is List"
    assert this_is([foo: 1, bar: 2]) == "This is List"
  end

  test "Tuples in guards", _ do
    assert this_is({:error}) == "This is Tuple"
    assert this_is({:ok, "foo"}) == "This is Tuple with two elements"
  end

  test "Maps in guards", _ do
    assert this_is(%{:foo => "foo", "bar" => "bar"}) == "This is Map"
  end

  test "Functions in guards", _ do
    double = fn(x) -> x * 2 end
    remainder = &rem/2

    assert this_is(double) == "This is Function"
    assert this_is(remainder) == "This is Function with two arguments"
  end

  test "Multiple arguments in guards", _ do
    assert they_are(:ok, "foobar") == "They are Atom and Binary"
  end

end
```

## 注釈:Stringについて

Elixirは文字列についての扱いが若干ややこしく、学習を進める前に[Binaries, strings and char lists](http://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html)を熟読しておくと良い。

かいつまんで解説すると、Elixirで文字列と言えば、ダブルクォーテーションで囲まれた文字列で表される（i.e `"foobar"`）、UTF-8でエンコーディングされたバイナリである。また、String型というようなものは存在しないため、`is_string`というモノが仮にあったとしても、厳密にそれが文字列かどうかの保証はできない。従って、`is_binary/1`を使って文字列かどうかの大まかな判定を行うのがElixirでの習わしとなっている。

他方で、シングルクォーテーションで囲まれた文字列（i.e `'foobar'`）で表されるChar Listというものがあるが、これは主にErlangとの互換性を持つために用意された型である。

# あとがき

guards素敵すぎ。パターンマッチは言語機能として非常に強力で、簡潔に期待する引数を記述できる上、書いてて楽しいという俺得プログラマー得な機能。是非マスターして、かっこ良くて分かりやすいコードを書けるようにしたい。

# こんなのもあるよ

[[Elixir] Task QueueのExqをPhoenixで使う](http://qiita.com/FL4TLiN3/items/9b557473a5139b823ac8)
[[Elixir] PhoenixでPlugの自作](http://qiita.com/FL4TLiN3/items/18fa81c30fc9aeba7223)
[[Elixir] Phoenixで日付／時間を扱う](http://qiita.com/FL4TLiN3/items/5fcf57677a1c0123637d)