ElixirのGETTING STARTED（8.Modules）をやってみた

# URL
http://elixir-lang.org/getting-started/modules.html

# 試した環境
* Ubuntu Server 14.04 LTS 
* Erlang/OTP 18
* Elixir 1.0.4

# 導入
モジュールに複数の関数を入れてグループ化する。
これまでにいくつかのモジュールを見てきた。
例えばStringモジュールはこんな感じ。

```ex
iex> String.length "hello"
5
```

自分でモジュールを作るには、defmoduleマクロを使う。
そのマクロの中でdefマクロを使って関数を定義する。

```ex
iex> defmodule Math do
...>   def sum(a, b) do
...>     a + b
...>   end
...> end
{:module, Math,
 <<70, 79, 82, 49, 0, 0, 4, 124, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 123, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 2, 104, 2, ...>>,
 {:sum, 2}}
iex> Math.sum(1, 2)
3
```


# Compilation

モジュールをファイルへ書くことのメリットの多くは、それがコンパイルできて再利用できるところにある。
ファイル名がmath.exで、次の内容内容を持っているとする。

```ex:math.ex
defmodule Math do
  def sum(a, b) do
    a + b
  end
end
```

このファイルは、```elexirc```を使ってコンパイルできる

```ex
$ eliexirc math.ex
$ ls
Elixir.Math.beam  math.ex
```

こうすることで、定義されたモジュールのバイトコードを含むElixir.Math.beamという名前のファイルが生成される。

もう一度iexを開始すると、定義したモジュールが使えるようになる。（iexを開始した沖に同じディレクトリにあるバイトコードのファイルは自動的に読み込まれる。）

```ex
iex(1)> Math.sum(1,2)
3
```

Elixirのプロジェクトは通常3つのディレクトリで構成される。

* ebin - コンパイルされたバイトコードが入る
* lib - Elixirのコードが入る(.exファイル)
* test - テストが入る(.exsファイル)

実際のプロジェクトはmixというビルドツールがコンパイルと適切なパスのセッティングをうまくやってくれる。
学習目的のために、Elixirではコンパイルしたbeamファイルを再生せずに、柔軟性があるスクリプトモードというものも使える。

# Scripted mode

```.ex``` というElixirの拡張子の他に、スクリプティングのために ```.exs``` ファイルもサポートしている。
Elixirは２つのファイルを同じように扱う。違いは意図していることだけ。 ```.ex```ファイルはコンパイルされること意図しているが、 ```.exs```ファイルはコンパイルがなしでスクリプトとして使われる。例えば、```math.exs``` というファイルを作成することができる。

```ex:math.exs
defmodule Math do
  def sum(a, b) do
    a + b
  end
end

IO.puts Math.sum(1, 2)
```

そして、次のように実行できる

```sh
$ elixir math.exs 
3
```

math.exsファイルは、メモリ内でコンパイルされ、実行され、結果として3を表示する。バイトコードファイルは作られない。
今後の例を実行するような場合は、スクリプトファイルに書いて実行すると良い。

# Named functions

モジュールの中で、def/2を使って関数を定義したり、defp/2を使ってプライベート関数を定義できる。
def/2で定義した関数は別のモジュールから呼び出せるのに対し、プライベート関数はモジュール中からしか呼び出せない。

```ex
defmodule Math do
  def sum(a, b) do
    do_sum(a, b)
  end

  defp do_sum(a, b) do
    a + b
  end
end

IO.puts Math.sum(1, 2)    #=> 3が返ってくる
IO.puts Math.do_sum(1, 2) #=> UndefinedFunctionErrorになる
```

関数宣言はガードと複数の節が使える。もし関数に複数の節がある場合は、マッチする節があるまで順番に試す。引数が数値の0かそうでないかをチェックする関数を書くと次のようになる。

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

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

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

引数がどの節にもマッチしない場合は、エラーが発生する。

```ex
IO.puts Math.zero?([1,2,3]) #=> FunctionClauseErrorになる
```

# Function capturing

これまで関数を表現するのに、name/arityという記法を使いましたが、実はこの記法は、関数型として名前付き関数を取得するために使用することができる。

iexを開始して、math.exsで試すと次のようになる。

```ex
$ iex math.exs
```

```ex
iex> Math.zero?(0)
true
iex> fun = &Math.zero?/1
&Math.zero?/1
iex> is_function fun
true
iex> fun.(0)
true
iex> fun.(1)
false
iex> fun.([1,2,3])
** (FunctionClauseError) no function clause matching in Math.zero?/1
    math.exs:2: Math.zero?([1, 2, 3])
```

```is_function/1``` のようなローカル、もしくはインポートされた関数はモジュールを付けなくても、関数をキャプチャできる。

```ex
iex> fun2 = &is_function/1 
&:erlang.is_function/1
iex> fun2.(fun)
true
```

キャプチャ構文は関数定義のためのショートカットとしても使える。

```ex
iex> fun = &(&1 + 1)
#Function<6.54118792/1 in :erl_eval.expr/5>
iex> fun.(1)
2
```

&1は関数に渡された最初の引数を表す。上記の&(&1 + 1)は、fn x -> x + 1 end と同じ。この構文は短い関数定義をするときに有用。キャプチャ演算子&については[Kernel.SpecialForms](http://elixir-lang.org/docs/stable/elixir/#!Kernel.SpecialForms.html#&/1)
のドキュメントで詳しく知ることができる。


# Default arguments

名前付き関数では、デフォルト引数をサポートしている。

```ex
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
``` 

デフォルト値としてどんな式でも用意しておけるが、関数定義の時に評価されない。単に後で使うものとして格納されるだけ。関数が呼ばれる時で、その関数のデフォルト値が利用されるたびに、デフォルト値に設定した式が評価される。

```ex
defmodule DefaultTest do
  def dowork(x \\ IO.puts "hello") do
    x
  end
end
```

```ex
iex> DefaultTest.dowork 123 
123
iex> DefaultTest.dowork    
hello
:ok
```

もし、デフォルト値つきの関数に複数の節がある場合、デフォルト値を宣言するヘッダ部分を作っておくことを推奨する。

```ex
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
```

もしデフォルト値を使うなら、関数定義の上書きについては十分な注意が必要。
次のような例がある。

```ex:concat.ex
defmodule Concat do
  def join(a, b) do
    IO.puts "***First join"
    a <> b
  end

  def join(a, b, sep \\ "") do
    IO.puts "***Second join"
    a <> sep <> b
  end
end
```

上記のコードをコンパイルすると、次のようなワーニングが表示される。

```ex
$ elixirc concat.ex 
concat.ex:7: warning: this clause cannot match because a previous clause at line 2 always matches
```

2引数のjoin関数は常に最初のjoinの定義を呼び出すことになり、2番目のものは3つの引数が渡された時にしか呼びされないことをコンパイラが教えてくれる。

```ex
iex(1)> Concat.join("Hello", "world")
***First join
"Helloworld"
iex(2)> Concat.join("Hello", "world", "_")
***Second join
"Hello_world"
```

モジュールの簡単な導入はおしまい。