コンパイラは、コードを解析し、入れ子のタプルに変換する マクロでタプルを操作する
マクロは受け取った引数を評価しない
以下はそれ自身が内部表現になる
- アトム
- 数値
- リスト(キーワードリスト含む)
- バイナリ
- 2要素のタプル
上記以外は「3要素のタプル」で表現される
goh@goh% iex "macros/dumper.exs"
Erlang/OTP 21 [erts-10.1.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
:atom
1
1.0
[1, 2, 3]
"binaries"
{1, 2}
[do: 1]
{:{}, [line: 20], [1, 2, 3, 4, 5]}
[
do: {:__block__, [line: 23],
[
{:=, [line: 23], [{:a, [line: 23], nil}, 1]},
{:+, [line: 23], [{:a, [line: 23], nil}, {:a, [line: 23], nil}]}
]}
]
[do: {:+, [line: 35], [1, 2]}, else: {:+, [line: 37], [3, 4]}]
内部表現 = 抽象構文木
[関数名のアトム, 行数を表すキーワードリスト, 引数]
Kernel.SpecialForms.require(module, opts)
- module: 先読みするモジュール
- opts: オプション
マクロを実行するためにモジュールを要求する
現在のモジュールよりも先に require
で指定されたモジュールをコンパイルする
マクロはプログラム実行前に展開される
=>
require
は、あるモジュールで定義されたマクロを他のモジュールで使用する際に使われる
以下の条件を満たす場合、モジュールのどの部分からロードしてよいのかわからなくなり、エラーが発生する
- あるモジュールと、それを呼び出すコードが同じファイルにある
- モジュールが、それを呼び出すコードと同じスコープにある
goh@goh% iex "macros/dumper_load_error.exs"
Erlang/OTP 21 [erts-10.1.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
** (CompileError) macros/dumper_load_error.exs:11: module My is not loaded but was defined. This happens when you depend on a module in the same context in which it is defined. For example:
defmodule MyApp do
defmodule Mod do
end
use Mod
end
Try defining the module outside the context that uses it:
defmodule MyApp.Mod do
end
defmodule MyApp do
use MyApp.Mod
end
If the module is defined at the top-level and you are trying to use it at the top-level, this is not supported by Elixir
Kernel.SpecialForms.quote(opts, block)
- opts: オプション
- block: ブロック
ブロックの内部表現を返す
> quote do: :atom
:atom
> quote do: 1
1
> quote do: 1.0
1.0
> quote do: [1, 2, 3]
[1, 2, 3]
> quote do: "binaries"
"binaries"
> quote do: {1, 2}
{1, 2}
> quote do: [do: 1]
[do: 1]
> quote do: {1, 2, 3, 4, 5}
{:{}, [], [1, 2, 3, 4, 5]}
> quote do: (a = 1; a + a)
{:__block__, [],
[
{:=, [], [{:a, [], Elixir}, 1]},
{:+, [context: Elixir, import: Kernel], [{:a, [], Elixir}, {:a, [], Elixir}]}
]}
> quote do: [do: 1 + 2, else: 3 + 4]
[
do: {:+, [context: Elixir, import: Kernel], [1, 2]},
else: {:+, [context: Elixir, import: Kernel], [3, 4]}
]
quote
と「"」は似ている
あとに続くものを [文字列|コード] と解釈し、 [適切な表現|内部表現] を返す