スポンサーリンク

2015年8月22日

[Elixir]モジュールの基本を習得する

とある錬金術師の万能薬(Elixir)

Goal

Elixirのモジュールを習得する。
また、アトリビュート(属性)も習得する。

Dev-Environment

OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4

Wait a minute

ようやっとたどり着きました。
今回はモジュールについて学んでいきます。
ついでなので、アトリビュート(属性)についても学んでいきます。
使い方だけなので、ここまできた方々なら理解するのに困難なことはないでしょう。

Index

Modules
|> Using module
|> Function capturing
|> Using attributes
|> Extra

Using module

モジュールと関数を定義してみましょう。

ファイル: math.ex

Example:
defmodule Math do
  def add(x, y) do
    x + y
  end

  defp zero?(value) do
    value == 0
  end
end
Description:
defmodule、def、defpは全部マクロで作られている。

・モジュールの定義

モジュールの定義の仕方。
Example:
defmodule モジュール名 do
  ...
end

・名前付き関数の定義

名前付き関数の定義の仕方。
Example:
defmodule モジュール名 do
  def 関数名(引数) do    ...  endend

・プライベートな関数の定義

モジュールの中でだけ使える関数を定義できます。
プライベートな関数の定義の仕方。
Example:
defmodule モジュール名 do
  defp 関数名(引数) do
    ...
  end
end

・関数の示し方

「関数名/アリティ」で示す。
(アリティは引数の数)
Example:
defmodule Math do
  def add(x, y) do
    ...
  end
end
上記の場合、addを示す場合は・・・add/2となる。
もう少し親切に示すなら、Math.add/2としてあげれば、
何のモジュールの関数であるかも分かるようになる。

・ガードについて

caseで使ったように、関数でもガードを使うこともできます。
Example:
defmodule モジュール名 do
  def 関数名(a) when is_atom(a) do
    ...
  end
end
ガードについて詳しく知りたい場合、以下を参照して下さい。
参考: elixir-lang - case, cond and if (Expressions in guard clauses)

・デフォルト値について

引数にデフォルトの値を設定することができます。
Example:
defmodule モジュール名 do
  def 関数名(a \\ 0) do
    ...
  end
end
複数のデフォルト値を設定する一例。
Example:
defmodule モジュール名 do
  def sample(a \\ 0, b \\ 1)  def sample(a, b) do
    ...
  end
end

・コンパイル

.exファイルのコンパイルについて記述します。
Example:
>elixirc [file_name].ex
上記を実行すると、Elixir.[module_name].beamファイルが生成されます。
また、iexの実行したディレクトリに.beamファイルがあれば自動で読み込んでくれる。

・スクリプト実行

.exsファイルのスクリプト実行について記述します。
Example:
>elixir [file_name].ex

・iexで直接利用する

iexで直接使ってみましょう。
Example:
>iex [file_name].ex
ビルド関連は、mix(ビルドツール)が上手いことやってくれるので、
今のところ(私は)あまり活用していません。
精々がiexで動作検証といったところでしょうか?
実行は割愛します。

Function capturing

関数のキャプチャについて。
使い方を見るのが一番早いので、実行して試してみる。
Example:
>iex math.ex
上の方で作成したMathモジュールの関数をキャプチャしてみる。
iex> fun = &Math.add/2
&Math.add/2
iex> is_function(fun)
true
iex> fun.(1, 1)
2
ローカルな関数、インポートされた関数をキャプチャしてみる。
(この場合、モジュール名はなくても問題ない)
iex> &is_function/1
&:erlang.is_function/1
iex> (&is_function/1).(fun)
true
キャプチャ構文を利用して、関数のショートカットとして使ってみる。
iex> fun = &(&1 + &2)
&:erlang.+/2
iex> fun.(1, 1)
2
無名関数のように見えますね。
実際、以下の無名関数と上記のキャプチャ構文は同じ結果を出力しています。
iex> fun = fn(x, y) -> x + y end
#Function<12.90072148/2 in :erl_eval.expr/5>
iex> fun.(1, 1)
2

Using attributes

モジュールのアトリビュートについて。
3つの目的がある。
  • 注釈
  • 定数
  • 一時的な貯蔵
一時的な貯蔵をやるには知識/経験共に不足しているため実施しない。

・注釈

  • @moduledoc ・・・ モジュールのドキュメントを記述する
  • @doc ・・・ 関数やマクロのドキュメントを記述する
  • @behaviour ・・・ ユーザ定義かOTP定義の振舞なのか区別するために使われる
  • @before_compile ・・・ モジュールがコンパイルされる前に実行されるフック。(コンパイル直前にモジュールへ関数を注入できるらしい)
  • @spec ・・・ 関数の仕様を記述する
  • @callback ・・・ behaviourのコールバック仕様を記述する
  • @type ・・・ @specの中での型を定義する
  • @typep ・・・ @specの中でのプライベートな型を定義する
  • @opaque ・・・ @specの中での未確定な型を定義する
利用頻度の高そうなものの一例を記述する。
Example:
defmodule Math do
  @moduledoc """
  Math module is ...

  ## Examples

      iex> Math.add(1, 1)
      2

  """

  @doc """
  add/2 function is ...
  """
  def add(x, y) when is_float(x) and is_float(y) do
    x + y
  end

  ...

  @doc """
  sample/2 function is ...
  """

  @type action :: :walk | :run | :hop | :step | :jump
  @spec sample(action, Keyword.t) :: %{action => Keyword.t}
  def sample(action, opts \\ []) do
    ...

    Map.put_new(%{}, action, opts)
  end
end
Description:
@typeの定義の仕方。
Example:
@type タイプ名 :: 型の内容
@specの定義の仕方。
引数の部分には@typeで定義したタイプ名が使える。
Example:
@spec 関数名(引数) :: 戻り値

・定数

定数の定義の仕方。
defmodule Math do
  @zero 0

  def get_zero do
    @zero
  end
end
Caution:
定数の値は、コンパイルするときに読み込まれます。

Extra

複数の引数をガードで使うには・・・
(and以外にもorとか使えます)
Example:
defmodule Math do
  def add(x, y) when is_number(x) and is_number(y) do
    x + y
  end

  ...
end
また、関数ではガードと複数の句に対応している。
以下のような場合、Elixirではマッチするまで順番に試してくれる。
Example:
defmodule Math do
  def add(x, y) when is_float(x) and is_float(y) do
    x + y
  end

  def add(x, y) when is_number(x) and is_number(y) do
    x + y
  end

  ...
end
どの関数にもマッチしない場合はエラーになる。

Speaking to oneself

やるだけならGetting Startも大して時間はかからないんだが・・・
まとめながらやって行くのは、やっぱり時間かかりますね。
後の怠惰のために、今の勤勉をってところですね。
ある一定以上まで到達すれば、きっと楽になります。

Bibliography

人気の投稿