Elixirのちょっと特殊な文法のまとめ

Elixirを勉強した時に感じた、Elixirのちょっと特殊な文法を書いています。
特殊かどうかは人それぞれですが、あくまで個人的な考えです。

## **doブロック**
複数の式をグループ化し、他のコードに渡すためのものです。
モジュールや名前付き関数の定義、制御構造などで使われます。

```elixir
def double(n) do
  n * 2
end
```
`do..end`はただの糖衣構文で、次のようにも書けます。

```elixir
def double(n), do: n * 2
```

括弧でグループ化することで、do: に複数行を渡すことができます。

```elixir
iex> if true, do: (
...>   a = 1 + 2
...>   a + 10
...> )
13
```
`do...end`はコンパイル時に`do:`形式に変換されます。`do:`形式は単なるキーワードリストの一単語です。

```elixir
iex> if false, do: :this, else: :that
:that
```
主に、一行のブロックのときには`do:`形式、複数行のときには`do...end`形式を使います。

## **パイプライン演算子(|>)**
左辺の関数の戻り値が右辺の関数の第一引数として渡されます。
例えば、リストをソートして反転した上で、カンマで連結するといった処理を行うとして
パイプ演算子を利用しない場合、次のように処理の順番と逆順に記述することになります。

```elixir
iex> Enum.join(Enum.reverse(Enum.sort([1,3,2,5,4])), ",")
"5,4,3,2,1"
```

パイプ演算子を利用すれば、処理の順番通りに記述できるので分かりやすいです。

```elixir
iex> [1,3,2,5,4] |> Enum.sort |> Enum.reverse |> Enum.join(",")
"5,4,3,2,1"
```

## **<>演算子**
```elixir:文字列の結合
iex> "hoge" <> "fuga"
"hogefuga"
```

## **++ 演算子**
```elixir:リストの連結
iex> [1, 2] ++ [3, 4, 5]
[1, 2, 3, 4, 5]
```

## **-- 演算子**
```elixir:リストの減算
iex> [1, 2, 3, 4, 5] -- [5, 6]
[1, 2, 3, 4]
```

## **hd と tl 関数**
リストの頭部(head)と尾部(tail)を取得します。

```elixir
iex> hd [1, 2, 3, 4, 5]
1
iex> tl [1, 2, 3, 4, 5]
[2, 3, 4, 5]
```

## **cons 演算子(|)**
右辺がリストの場合、左辺の値を右辺のリストの先頭に追加します。

```elixir
iex> a = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex> [0 | a]
[0, 1, 2, 3, 4, 5]
```
リストを頭部と尾部に分けるのに`|`を使うこともできます。

```elixir
iex> [head | tail] = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex> head
1
iex> tail
[2, 3, 4, 5]
```

## **無名関数**
文字列やアトムなどと同様に「値」の一種です。次のように無名関数を定義して変数`f`にセットします。

```elixir
iex> f = fn (a, b) -> a + b end
iex> f.(2, 3)
5
```

## **キャプチャ演算子(&)**
関数捕捉演算子とも呼ばれます。`&`を付けることで、関数を無名関数に変換することができます。

```elixir:関数のキャプチャ
iex> f = &Enum.sort/1
iex> f.([1, 3, 2, 5, 4])
[1, 2, 3, 4, 5]
```
`&`のもう一つの用法は無名関数の省略記法です。引数を`&1`、`&2`など（プレースホルだーと呼ぶ）として扱うことができます。

```elixir:無名関数の省略記法
iex> f = &(&1 + &2)
iex> f.(2, 3)
5
```

## **ガード節**
`when`で始まる式を付加することができます。

```elixir:case式のガード節
iex> case {1, 0, 3} do
...>   {1, x, 3} when x > 0 -> "マッチする"
...>   _ -> "マッチしない"
...> end
"マッチしない"
```
関数の引数に条件を付けることで、同じ関数名で異なる処理を実現することができます。

```elixir:関数のガード節
defmodule Hoge do
  def hello(names) when is_list(names) do
    for name <- names do
      Hoge.hello(name)
    end
  end
 
  def hello(name) do
    IO.puts "Hello, #{name}"
  end
end
 
iex> Hoge.hello(["Alice", "Bob"])
Hello, Alice
Hello, Bob
```
無名関数でもガード節を使うことができます。

```elixir:無名関数のガード節
double = fn
  n when is_integer(n) -> n * 2
  x when is_float(x) -> x * 2
  s when is_binary(s) -> s <> s
end
 
iex> double.(1)
2
iex> double.(0.5)
1.0
iex> double.("abc")
"abcabc"
```
ガード節に使える式はこちらです。
https://hexdocs.pm/elixir/master/guards.html

## **first..last**
`1..10`のように範囲(Range)を定義します。内部では構造体として表現されます。
範囲の作成とマッチングの最も一般的なフォームは`Kernel`から自動インポートされる`../2`マクロによってです。

>first..last
>Returns a range with the specified first and last integers

```elixir:範囲のパターンマッチ
iex> range = 1..10
1..10
iex> first .. last = range
1..10
iex> first
1
iex> last
10
iex> range.__struct__
Range
```

## **with式**
マッチング節(matching clauses)の結合をするために使います。
全ての節がマッチしたら、`do`ブロックが実行されてその結果を返します。

```elixir:マッチ成功
iex> width = nil
iex> opts = %{width: 10, height: 15}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      double_width = width * 2,
...>      {:ok, height} <- Map.fetch(opts, :height),
...>      do: {:ok, double_width * height}
{:ok, 300}
iex> width
nil
```
`with`式の内側の変数は`with`式の中でのみ有効です。
そのため、内側の変数`width`は外側のスコープの変数`width`には影響しません。
`double_width`は`do`ブロックでもスコープに入っています。
マッチに失敗すると評価を止めて右辺のマッチしない場合の値を返します。

```elixir:マッチ失敗
iex> opts = %{width: 10}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      {:ok, height} <- Map.fetch(opts, :height),
...>      do: {:ok, width * height}
:error
```
この場合は、`:height`がないので`Map.fetch/2`は`:error`を返します。