Elixir 文法 メモ


*※この記事はとても古くなっています。注意してください。*


個人的なメモです。


[Get Started](http://elixir-ja.sena-net.works/getting_started/1.html) を読みながらまとめました。

流し読みすれば雰囲気くらいはつかめるかもしれません。


## 匿名関数

``` elixir
add = fn a, b -> a + b end
is_function add, 1 # false
add.(1, 2) # 3
```

### 即時実行
``` elixir
(fn -> x = 0 end).()
```

## bool
Elixirでは`false`と`nil`だけがfalseとして扱われます．他の全てはtrueと評価されます．


# リスト と タプル
* リスト `[1, true, 2]`
* タプル `{false, 1, "abc"}`

どんな型も入れられる。

## リスト [ ]
> [1, 2, true, "abc"]

・連結したノードで、要素の一つ一つが次の要素のアドレスを指してる

つまり `list = [1|[2|[3|[]]]]` → `[1, 2, 3]`

※ノードというよりコンスと呼ぶらしい

* **要素アクセスやサイズ取得は遅い**
* **先頭に追加するのは速い**

`[0] ++ list` -> 速い

`list ++ [4]` -> 遅い ← 最初から最後まで見に行かなきゃいけないから


### --演算子
※先にあるものから引かれる

`[1, true, false, 1, 2, 3] -- [1,2,3]` → `[true, false, 1]`

hd/1  ：headを取得

tl/1  ：tailを取得


## タプル { }
> {1, 2, true, "abc"}

* 連続したメモリに保存
* **indexでのアクセスやサイズ取得が速い**
* **要素の追加や変更は新しいタプルをつくるから遅い**

### 要素の変更
> put_elem(たぷる, インデックス, 内容)

※新しいタプルを返す



## Elixir上での長さの呼び方
* 計算が必要なもの → length
* 既に計算されているもの → size


# 演算子

## and, or, not  -> 真理値のみ受け付ける
`true and true`

`1 and true` ← エラー


## &&, ||, !    どんな型も受け付ける
**falseとnil 以外は true**

※ 評価されて帰ってくるだけ


## == と ===
**整数と浮動小数点を厳密に見るかどうか**

## <, > での 異なる型の比較をした場合
number < atom < reference < functions < port < pid < tuple < maps < list < bitstring
になる

#マッチ演算子 =

* 変数が左辺にあれば変数が割り当てられる

`x = 1`

* 式として妥当なら返す

`1 = x`  → 1

* 式として妥当でなければMatchErrorが発生する

`2 = x` → エラー

`1 = y`    → yは未定義だからエラー


## パターンマッチング
> {name, age, tall} = {:jon, 12, 164}

> name # jon

※もちろん型やサイズがマッチしていなければエラーを返す

### headとtailに分ける
> [h | t] = [1, 2, 3]

「|」 は [0|list] のようにリストを生成することも出来る


### Elixir では 変数は再束縛される
> x = 1

> x = 2

### ^ 演算子
**再束縛ではなく、その変数をマッチさせたい時に使う**
> ^x = 2

#### ※マッチの左側で関数を呼ぶことはできない
```
 length([1,[2],3]) = 3
** (CompileError) iex:1: illegal pattern
```

### _　演算子
**受け取らない**
> {x, _} = {:ok, "gomi"}

# case, cond, if

## case

``` elixir
case {1, 2, 3} do
    {4, 5 ,6} -> "この場合マッチしない"
    {1, x, 3} -> "これにマッチする"
    _ -> "どれでもマッチ"
end
# 2
```

### すでにある変数とマッチするときは ^ が必要

``` elixir
iex> x = 1
1
iex> case 10 do
...>   ^x -> "Won't match"
...>   _  -> "Will match"
...> end
```

### guardの指定
whenとかで条件を拡張できる構文。

``` elixir
iex> case {1, 2, 3} do
...> {1, x, 3} when x > 0 -> "マッチする"
...> _-> "マッチしない"
...> end
```

#### ガードにはいろんな式が使える。
* in
* and, or, not
* is_atom, is_binary...
* hd, tl, trunc, tuple_size...

※ ガードの中で起きたエラーは単純にガードの失敗とみなされてガードの外には影響しない


**どの句にもマッチしなければエラーになる**

``` elixir
iex> case :ok do
...>   :error -> "Won't match"
...> end
# ** (CaseClauseError) no case clause matching: :ok
```

**匿名関数でも句やガードを持てる**

``` elixir
iex> f = fn
...>   x, y when x > 0 -> x + y
...>   x, y -> x * y
...> end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> f.(1, 3)
4
iex> f.(-1, 3)
-3
```

## cond
trueになるまで複数の条件をチェックする構文。

``` elixir
iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...>   true ->
...>     "全部falseだった場合" #何もtrueにならないとエラーになるからこうする
...> end
"But this will"
```

#### condではnilとfalse以外はtrue

``` elixir
iex> cond do
...>   hd([1,2,3]) ->
...>     "nilとfalse以外はtrue"
...> end
"nilとfalse以外はtrue"
```




## if, unless
``` elixir
if true do
    "ok"
end
```
条件文がfalseかnilならnilが返って来て実行されない。
unlessはifの逆。


## else
``` elixir
if false do
    "this won't be seen"
else
    "this will"
end
```

> メモ: この言語でif/2やunless/2がマクロとして実装されているのがおもしろい点です;これらは他の様々な言語でそうであるような特別な言語構造ではありません．モジュールKernelのドキュメントでif/2のドキュメントやソースを調べることができます．モジュールKernelには他にも演算子+/2や関数is_function/2といったような，あなたがコードを書くときにデフォルトで自動importされて使えるようになっているものが定義されています．

## do

``` elixir
if true do
    a = 1 + 2
end
```

### キーワードリスト
``` elixir
if true, do: 1 + 2
```

``` elixir
if false, do: "this", else: "that"
```

``` elixir
if true, do: (
  a = 1 + 2
  a + 10
)
```

## 引数にifを渡す
``` elixir
is_number(if true do
 1 + 2
end)
```

# UTF-8
> byte_size "a"

1

> byte_size "å"

2

> byte_size "🎃"

4

# バイナリ
`byte_size <<0, 1, 2, 3>>`

4

## バイナリと文字列
`<<100>>`
"d"

`String.valid?(<<100, 101, 102>>)`
true

## バイナリの結合
`<<0, 1>> <> <<2, 3>>`
↓
`<<0, 1, 2, 3>>`


### ヌルバイト`<<0>>を結合させて文字列のバイナリ表現を見る

`"hełło" <> <<0>>`
↓
`<<104, 101, 197, 130, 197, 130, 111, 0>>`


## 文字リスト

二重引用符で囲まれたものは文字列**(つまりバイナリ)**
**単一引用符で囲まれたものは文字のリスト(つまりリスト)**

>'hełło'

[104, 101, 322, 322, 111]

>is_list 'hełło'

true

## 文字列、文字リストの変換
> to_char_list "hełło"

[104, 101, 322, 322, 111]

> to_string 'hełło'

"hełło"

> to_string :hello

"hello"

> to_string 1

"1"

# キーワードリスト [hoge: foo, ...]
"最初の要素がアトムになっているタプル"のリスト。
連想データ構造。

#### [{あとむ, 要素}, {あとむ, 要素}, ...] って感じ
> list = [{:a, 1}, {:b, 2}]

#### こうもかける
> list = [a: 1, b: 2]

#### アクセス
> list[:a] 


### ++演算子で追加できる
> list ++ [c: 3]

### ※同じキーがある場合は前のが取得される
list = [a: 0, a: 1, b: 2]
> list[:a]

0

## キーワードリストの特徴
* **キーの順序を開発者が指定したとおりに保持する**
* **キーを複数回与えることができる**

## if関数 も キーワードリストを受け取っている
実はifのこの書き方は、if関数の最後の引数にキーワードリストを最後に渡してる。
> if false, do: "abc", else: 123

↓これと同じ

> if(false, [do: "abc", else: 123])



## キーワードリストにもパターンマッチできる

``` elixir
iex> [a: a] = [a: 1]
[a: 1]
iex> a
1
iex> [a: a] = [a: 1, b: 2]
** (MatchError) no match of right hand side value: [a: 1, b: 2]
iex> [b: b, a: a] = [a: 1, b: 2]
** (MatchError) no match of right hand side value: [a: 1, b: 2]
```
---
**キーワードリストを操作するKeywordモジュールがあります。**

## キーワードリストとマップの使い分け
キーワードリストは単にリストなので、長いリストはキーを見つけるのがより長くなり、要素を数えるのも長くなる。
だからキーワードリストは主にオプションに使われる。

もし沢山の要素を保持しなければならなかったり、１つのキーが多くとも１つの値しか持たないことを保証したい場合はマップを使った方がいい。


# マップ %{:hoge => foo, ...}
> map = %{:a => 1, 2 => :b}

* **マップはキーをどんな値にもできる**
* **１つのキーが１つの値をもつ**
* **マップのキーは順番通りにならない**

## 同じキーを渡すと最後が勝つ
> %{1 => 1, 1 => 2}

%{1 => 2}

## キーが全部atomならキーワード構文が使える
> map = %{a: 1, b: 2}

## マップはパターンマッチングに使いやすい
キーワードリストとは対照的に使いやすい。

``` elixir
iex> %{} = %{:a => 1, 2 => :b}
%{:a => 1, 2 => :b}
iex> %{:a => a} = %{:a => 1, 2 => :b}
%{:a => 1, 2 => :b}
iex> a
1
iex> %{:c => c} = %{:a => 1, 2 => :b}
** (MatchError) no match of right hand side value: %{2 => :b, :a => 1}
```

## キーが全部atomなら使える構文
> map.a

とか

> %{map | :a => 2}

↓ 例

``` elixir
iex> map = %{:a => 1, 2 => :b}
%{:a => 1, 2 => :b}
iex> map.a
1
iex> %{map | :a => 2}
%{:a => 2, 2 => :b}
iex> %{map | :c => 3}
** (ArgumentError) argument error
```
上にあるアクセスと更新のどちらの構文でも既にあるキーを必要とします．例えば最後の行ではマップにcがないので失敗しています．これはマップに既にキーがあることをあなたが期待している場合にすごく便利に使うことができます．

---
**マップを操作するMapモジュールがあります。**

# キーワードリストもマップも「Dicts」
ディクショナリ。
ディクショナリはインターフェイスのようなもの。
キーワードリストもマップも、ディクショナリのインターフェイスを実装している。
※ Elixirではインターフェイスをbehaviours(ビヘイビア)と呼ぶ。

``` elixir
iex> keyword = []
[]
iex> map = %{}
%{}
iex> Dict.put(keyword, :a, 1)
[a: 1]
iex> Dict.put(map, :a, 1)
%{a: 1}
```

# モジュール
``` elixir
defmodule Math do
  def sum(a, b) do
    a + b
  end
end
```

* **boolを返す関数には?をつける**
* **when句を使える**

``` elixir
defmodule Math do
  def zero?(0) do
    true
  end

  def zero?(x) when is_number(x) do
    false
  end
end

Math.zero?(0)  #=> true
Math.zero?(1)  #=> false

Math.zero?([1,2,3])
#=> ** (FunctionClauseError)
```

## **引数の数が違う関数は別の関数として扱われる**

> is_function/1
> is_function/2

のように表す

## 関数のキャプチャ
&をつけることで、関数を代入したりできるようになる。
> f = &Math.add/1
> f.(1, 2)

## キャプチャ構文は関数を作るときのショートカットにもなる
> add = &(&1 + 1)
> add.(1)     #2

## デフォルト引数
>   def join(a, b, sep \\ " ") do

``` elixir
defmodule Concat do
  def join(a, b, sep \\ " ") do
    a <> sep <> b
  end
end

IO.puts Concat.join("Hello", "world")      #=> Hello world
IO.puts Concat.join("Hello", "world", "_") #=> Hello_world
```

## 複数句がある場合は最初にデフォルト引数を決めておくことができる

``` elixir
defmodule Concat do
  def join(a, b \\ nil, sep \\ " ")

  def join(a, b, _sep) when is_nil(b) do
    a
  end

  def join(a, b, sep) do
    a <> sep <> b
  end
end

IO.puts Concat.join("Hello", "world")      #=> Hello world
IO.puts Concat.join("Hello", "world", "_") #=> Hello_world
IO.puts Concat.join("Hello")               #=> Hello
```


forとかないから再帰する


## Enumモジュールの mapとreduce

map : 配列の全要素に関数を適用
reduce : 配列の全要素に関数を適用して足す


``` elixir
iex> Enum.reduce([1, 2, 3], 0, fn(x, acc) -> x + acc end)
6
iex> Enum.map([1, 2, 3], fn(x) -> x * 2 end)
[2, 4, 6]

# キャプチャ構文
iex> Enum.reduce([1, 2, 3], 0, &+/2)
6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
```
Enumモジュールにある関数はEnumerableプロトコルを実装したどんなデータ型でも動作するようになっています．

# 範囲
``` elixir
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.reduce(1..3, 0, &+/2)
6
```
# パイプライン
``` elixir
1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
```

100000までの数を三倍して奇数だけにして足す。

Enumの関数の多くはEnumerableを受け取って１つのリストを返します。
つまり複数の操作をした時に結果が出るまで全ての操作が中間リストを作るということになる。

それは流石にヤバイ。

例えば以下を実行すると物凄く時間かかる。終わらない。
> 1..1000000000 |> Enum.map(&(&1 * 3))

そこでStreamモジュールというものを使う。


# Streamモジュールをつかうと、一連の処理を作ってくれる。
大きいEnumerableや無限かもしれない集まりを扱うのに便利。

## StreamをつくってEnum.takeで少しだけ実行する
``` elixir
> s = 1..1000000000 |> Stream.map(&(&1 * 3))
#Stream<[enum: 1..1000000000, funs: [#Function<45.113986093/1 in Stream.map/2>]]>

> Enum.take(s, 3)
[3, 6, 9]
```



## Stream.cycle
Enumerableを無限に繰り返す。

``` elixir
iex> stream = Stream.cycle([1, 2, 3])
#Function<15.16982430/2 in Stream.cycle/1>

iex> Enum.take(stream, 10)
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
```

## Stream.unfold

初期値をとって、関数を再帰的に実行していく。
関数で{要素, 次の値}を返す。

> Stream.unfold(5, fn 0 -> nil; n -> {n, n-1} end) |> Enum.to_list()

[5, 4, 3, 2, 1]


## ファイルから10行とる
> iex> stream = File.stream!("path/to/file")
> iex> Enum.take(stream, 10)


# プロセス
Elixirでは全てのコードはプロセスの内部で動きます．プロセス同士は独立，並行して動き，メッセージパッシングでやり取りします．プロセスはElixirにおける並行の基本となるばかりではなく，分散や高可用なプログラムの構築にも役立ちます．

ElixirのプロセスをOSのプロセスと混同してはいけません．プロセスは(他の多くのプログラミング言語におけるスレッドとは異なり)メモリとCPUにとって非常に軽量です．ですから，同時に動作する数千のプロセスを保持することは特別珍しいことではありません．

## Spawn
プロセスを生み出し、関数を開始、PIDを返す。

> iex> spawn(fn -> 1 + 2 end)
 # PID<0.43.0>

### プロセスが生きてるか確認
> iex> Process.alive?(pid)
false

### self/0 で自分のプロセスのPIDを入手
> iex> self()
 #PID<0.58.0>
> iex> Process.alive? self()
> true


## send
↓自分のプロセスにメッセージを送る

``` elixir
send self(), {:abc, "dope"}
# {:abc, "dope"}
```

## receive
sendされたメッセージはメールボックスに入る。

``` elixir
receive do
  {:abc, msg} -> msg
  {:woo, msg} -> "aaa"
end
# "dope"
```
もしパターンにマッチするメッセージがメールボックスに無ければ，現在のプロセスはマッチするメッセージがくるまで待ち続けます．タイムアウトを指定することもできます:


``` elixir
receive do
  {:wtf, msg} -> msg
  {:woo, msg} -> "aaa"
  after
    1000 -> "１秒待ったけど何も来なかった..."
end
```

## flush/0 でメールボックス全部表示&消す
``` elixir
iex> send self(), :hello
:hello
iex> flush()
:hello
:ok
```

## 独立してるので子プロセスでエラー起きても落ちないスゴイ！！
> iex> spawn fn -> raise "oops" end

[error] Error in process <0.58.0> with exit value: ...

## spawn_link 使うことで同時に親も落ちさせることもできる
> spawn_link fn -> raise "oops" end

Process.link/1を呼べばリンクを手動で行うこともできます．

## "早く失敗する"はElixirでソフトウェアを書く際の一般的な指針
>プロセスとリンクは可用性の高いシステムを構築するのに大事な役割を担っています．Elixirのアプリケーションではしばしば，プロセスが死んでしまった際に検知し，同じ場所で新しいプロセスを動かすため，私たちが作るプロセスとスーパーバイザー(監視役)をリンクさせます．これができるのはプロセスがデフォルトでは何も共有しないためです．そしてもしプロセスが独立しているなら，プロセス内での失敗が他のプロセスをクラッシュさせたり状態を壊したりすることは絶対にありません．

> 他の言語では例外は受けとったり操作することが求められますが，Elixirではスーパーバイザーがシステムを再起動してくれるであろうため，プロセスは失敗するがままでかまいません．"早く失敗する"はElixirでソフトウェアを書く際の一般的な指針です！

# 状態

設定を保持したり、メモリを保持するには？
↓
プロセスをつくってそこに保存する！！！

## キーと値を保持するモジュールを作ってみる
KV(key-value)

``` elixir
defmodule KV do
  def start_link do
    {:ok, spawn_link(fn -> loop(%{}) end)}
  end

  defp loop(map) do
    receive do
      {:get, key, caller} ->
        send caller, Map.get(map, key)
        loop(map)
      {:put, key, value} ->
        loop(Map.put(map, key, value))
    end
  end
end
```

#### 起動
> {:ok, pid} = KV.start_link

#### 保存
> send pid, {:put, :name, "taro"}

#### 取得
> send pid, {:get, :name, self()}
> flush()


## Agentモジュール
Elixirが提供してる状態保存のモジュール。

#### 起動
> {:ok, pid} = Agent.start_link(fn -> %{} end)

#### 保存
> Agent.update(pid, fn map -> Map.put(map, :name, "taro") end)

#### 取得
> Agent.get(pid, fn map -> Map.get(map, :name) end)




# ファイル系モジュール
* File: ファイルの読み書き
* Path: ファイルパス



# !(バン)

読み込みが必ず成功するときはバンをつける。
バンをつけて読み込みに失敗するとエラーになる。
> File.read "hello"

{:ok, "world"}

> File.read! "hello"

"world"




### こう書いてはいけない
`{:ok, body} = File.read(file)`

こう書く

``` elixir
case File.read(file) do
  {:ok, body} -> # handle ok
  {:error, r} -> # handle error
end
```

# グループリーダー
どのプロセスにもグループリーダーがある。
`:stdio`と書いた場合、実際にはグループリーダーへメッセージを送っている。
グループリーダーはSTDIOをファイルディスクリプタに書き込む。


``` elixir
iex> IO.puts :stdio, "hello"
hello
:ok
iex> IO.puts Process.group_leader, "hello"
hello
:ok
```

グループリーダーはプロセスごとに設定できる。


# alias


``` elixir
defmodule Math do
  alias Math.List, as: List
end
```

asを省略すると最後の部分を自動的に設定するので
これも同じ意味になる。

`alias Math.List`


## lexically scoped
レキシカルスコープ。
関数の中でエイリアスを設定した場合はその関数の中でのみ有効になる。

``` elixir
defmodule Math do
  def plus(a, b) do
    alias Math.List
    # ...
  end

  def minus(a, b) do
    # ...
  end
end
```

# require

マクロとはコンパイル時に実行して展開されるコード片。
マクロをつかうためには`require`しないと使えない。

下記の例では`Integer.is_odd`はマクロとして実装されているため`require`する必要がある。

``` elixir
iex> Integer.is_odd(3)
** (CompileError) iex:1: you must require Integer before invoking the macro Integer.is_odd/1
iex> require Integer
nil
iex> Integer.is_odd(3)
true
```

※requireもレキシカルスコープ。


# import
importを使うと、そのモジュールの 関数やマクロ を モジュール名を省略して書くことができる。
モジュールをimportすると自動的にrequireする。



``` elixir
iex> import List, only: [duplicate: 2]
nil
iex> duplicate :ok, 3
[:ok, :ok, :ok]
```

上記の例では List.duplicate/2 のみをimportしてる。


全てのマクロをインポートする場合
> import Integer, only: :macros

全ての関数をインポートする場合
> import Integer, only: :functions

※importもレキシカルスコープ。



# エイリアスの実態はatom

``` elixir
iex> is_atom(String)
true
iex> to_string(String)
"Elixir.String"
iex> :"Elixir.String"
String
```

## モジュールはatomで表現されている

``` elixir
iex> :lists.flatten([1,[2],3])
[1, 2, 3]
iex> mod = :lists
:lists
iex> mod.flatten([1,[2],3])
[1,2,3]
```


## デフォでエイリアスされてる

``` elixir
defmodule Foo do
  defmodule Bar do
  end
end
```

実は、これは↓と同じ

``` elixir
defmodule Elixir.Foo do
  defmodule Elixir.Foo.Bar do
  end
  alias Elixir.Foo.Bar, as: Bar
end
```




# Module attributes

「@」アトリビュート機能をつかってモジュールにドキュメントなどを埋め込むことができる。

「"""」でヒアドキュメント。
ヒアドキュメント内ではMarkdown形式で書ける！


``` elixir
defmodule Math do
  @moduledoc """
  Provides math-related functions.

  ## Examples

      iex> Math.sum(1, 2)
      3

  """

  @doc """
  Calculates the sum of two numbers.
  """
  def sum(a, b), do: a + b
end
```

[ExDoc](https://github.com/elixir-lang/ex_doc)と呼ばれているドキュメントからHTMLページを生成するためのツールも提供しています。

## 定数としても使える

``` elixir
defmodule MyServer do
  @initial_state %{host: "147.0.0.1", port: 3456}
  IO.inspect @initial_state
end
```
※値が入るのはコンパイル時


# 構造体

構造体は、マップのフィールドの存在をコンパイル時に保証する。

定義

``` elixir
defmodule User do
  defstruct name: "john", age: 27
end
```


↓インスタンス生成

`%User{}`


構造体はただのマップ。

``` elixir
> is_map(%User{})
true
```


構造体のupdate

``` elixir
iex> john = %User{}
%User{age: 27, name: "john"}
iex> john.name
"john"
iex> meg = %{john | name: "meg"}
%User{age: 27, name: "meg"}
iex> %{meg | oops: :field}
** (ArgumentError) argument error
```

↑ 存在しないフィールドに対してはupdateできない。



構造体のパターンマッチング

``` elixir
iex> %User{name: name} = john
%User{age: 27, name: "john"}
iex> name
"john"
iex> %User{} = %{}
** (MatchError) no match of right hand side value: %{}
```


構造体はマップの中に`__struct__`というフィールドを持っている

``` elixir
iex> john.__struct__
User
```

だからパターンマッチングができる。


※構造体はディクショナリではない


# プロトコル

例えば、アプリケーションによっては，それがブランクであると考えられるべきときに真偽値を返すようなblank?プロトコルを規定することが重要になるかもしれません．

``` elixir
defprotocol Blank do
  @doc "Returns true if data is considered blank/empty"
  def blank?(data)
end
```

↓ それぞれの型へのBlankプロトコルの実装

``` elixir
# 整数は決してブランクにならない - Integers are never blank
defimpl Blank, for: Integer do
  def blank?(_), do: false
end

# 空リストのときだけブランクになる - Just empty list is blank
defimpl Blank, for: List do
  def blank?([]), do: true
  def blank?(_),  do: false
end

# 空のマップのときだけブランクになる - Just empty map is blank
defimpl Blank, for: Map do
  # Keep in mind we could not pattern match on %{} because
  # it matches on all maps. We can however check if the size
  # is zero (and size is a fast operation).
  def blank?(map), do: map_size(map) == 0
end

# アトムがfalseとnilのときだけブランクになる - Just the atoms false and nil are blank
defimpl Blank, for: Atom do
  def blank?(false), do: true
  def blank?(nil),   do: true
  def blank?(_),     do: false
end
```

↓ プロトコルが実装された型はblankで受け取れる

``` elixir
iex> Blank.blank?(0)
false
iex> Blank.blank?([])
true
iex> Blank.blank?([1, 2, 3])
false
```

##プロトコル実装をすることで構造体も受け取れるようになる

``` elixir
defimpl Blank, for: User do
  def blank?(_), do: false
end
```



## プロトコルのデフォルト実装
`@fallback_to_any`を`true`にすると全部trueを返すようになる。

``` elixir
defprotocol Blank do
  @fallback_to_any true
  def blank?(data)
end
```

そして型に `Any` を指定することもできる。

``` elixir
defimpl Blank, for: Any do
  def blank?(_), do: false
end
```

## すでにある色んなプロトコル


### EnumではEnumerableプロトコルを実装している型を受け取れる。

``` elixir
iex> Enum.map [1, 2, 3], fn(x) -> x * 2 end
[2,4,6]
iex> Enum.reduce 1..3, 0, fn(x, acc) -> x + acc end
6
```

### to_string では String.Charsプロトコルを実装している型を受け取れる。

``` elixir
iex> to_string :hello
"hello"
```

これも to_string

``` elixir
iex> "age: #{25}"
"age: 25"
```

tuple は String.Charsプロトコルを実装してないのでエラーになる。

``` elixir
iex> tuple = {1, 2, 3}
{1, 2, 3}
iex> "tuple: #{tuple}"
** (Protocol.UndefinedError) protocol String.Chars not implemented for {1, 2, 3}
```

### Inspectプロトコルを実装していれば inspect を使える。

``` elixir
iex> "tuple: #{inspect tuple}"
"tuple: {1, 2, 3}"
```

※iexで結果を表示するのにもinspectを使用している。

※ 評価された値が#から始まるときは，エリクサーの構文ではない方法でデータ構造を表しているという意味を表すならわしになっている


# エラー

## 普通のエラー

``` elixir
iex> :foo + 1
** (ArithmeticError) bad argument in arithmetic expression
     :erlang.+(:foo, 1)
```

## raiseを使うとわざとエラーを起こせる

#### raise/1でランタイムエラー

``` elixir
iex> raise "oops"
** (RuntimeError) oops
```

#### raise/2で他のエラーを起こせる

``` elixir
iex> raise ArgumentError, message: "invalid argument foo"
** (ArgumentError) invalid argument foo
```

## 自分でエラーを定義できる

``` elixir
iex> defmodule MyError do
iex>  defexception message: "default message"
iex> end
iex> raise MyError
** (MyError) default message
iex> raise MyError, message: "custom message"
** (MyError) custom message
```

## try rescue文でエラーを受け取る

``` elixir
iex> try do
...>   raise "oops"
...> rescue
...>   e in RuntimeError -> e
...> end
%RuntimeError{message: "oops"}
```

ただしほとんど使うことはないらしい。
たとえばElixirでの関数File.read/1は，ファイルを開くのに成功した/失敗した情報を含んだタプルを返すようになってるかららしい。


# Throw, catch
途中で処理をジャンプしたりする時につかう？

``` elixir
iex> try do
...>   Enum.each -50..50, fn(x) ->
...>     if rem(x, 13) == 0, do: throw(x)
...>   end
...>   "Got nothing"
...> catch
...>   x -> "Got #{x}"
...> end
"Got -39"
```

# exit
プロセスが死んだ時、`exit`という信号が送られる。
また、わざと`exit`を送ることで死ぬことができる。


``` 一瞬で死ぬプロセス
iex> spawn_link fn -> exit(1) end
#PID<0.56.0>
** (EXIT from #PID<0.56.0>) 1
```
↑「１」という値を送って死んでいる。


## exitはtry/catchでキャッチされる

```
iex> try do
...>   exit "I am exiting"
...> catch
...>   :exit, _ -> "not really"
...> end
"not really"
```

> try/catchを使うことが既に珍しいですが，イグジットをキャッチするのはもっと珍しいことです．



> exitシグナルはErlang VMで提供されている耐障害性において重要な部分を担っています．プロセスは通常，単にプロセスのexit信号を待つだけの監視プロセスを備えた監視ツリーにくみこまれて動作しています．監視プロセスがイグジット信号を受けとると，監視作戦が開始され，監視対象のプロセスは再起動させられます．

> 監視システムの構造自体がtry/catchやtry/rescueに似ているため，Elixirではそれらの構文があまり用いられていないのです．確実にエラーを拾うかわりに，エラーのあとに"早く失敗する"ことで監視ツリーがアプリケーションを既知の初期状態へと戻すことを保証しています．

# after

エラーが起きても必ずそのあとに実行してくれる。

```
try do
  raise "oops"
after
  IO.puts "あふたー"
end
↓
あふたー
** (MatchError) no match of right hand side value: {:error, :enoent}
```


※ try/catch/rescue/afterブロックの中で定義した変数は外では見えない


# for

```

iex> for n <- [1, 2, 3, 4], do: n * n
[1, 4, 9, 16]


iex> for n <- 1..4, do: n * n
[1, 4, 9, 16]


iex> values = [good: 1, good: 2, bad: 3, good: 4]
iex> for {:good, n} <- values, do: n * n
[1, 4, 16]


iex> require Integer
iex> for n <- 1..4, Integer.is_odd(n), do: n * n
[1, 9]


for dir  <- dirs,
    file <- File.ls!(dir),
    path = Path.join(dir, file),
    File.regular?(path) do
  File.rm!(path)
end

iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
[{213,45,132},{64,76,32},{76,0,0},{234,32,15}]
```

## into:
処理した結果の行き先。
↓下記の例では空文字以外の文字が""へ追加されていく。

```
iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"

```

セット，マップそして他のディクショナリも:intoオプションに渡せます．たいていの場合，:intoはCollectableプロトコルを実装してさえいればどんなものでも受けつけます．


# シギル
http://elixir-ja.sena-net.works/getting_started/19.html