Quoting
- Elixir のプログラムは
tuple
を伴った3つの要素に置き換えることができる。例えばsum(1, 2, 3)
があった場合は以下のように書き換えることができる。
- 以下、自分の環境だと
sum
なんかおらん!と言われるのでrem
とか適当なビルトイン関数に置き換えて試すといいかと。
{:sum, [], [1, 2, 3]}
- quote マクロを使うと式の構造を見ることができる
iex> quote do: sum(1, 2, 3)
{:sum, [], [1, 2, 3]}
- 1つ目の要素は関数名のatom、2つ目はメタデータのリスト、3つ目は引数のリストとなる
operator
も同様に確認できる。
iex> quote do: 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}
iex> quote do: %{1 => 2}
{:%{}, [], [{1, 2}]}
iex> quote do: x
{:x, [], Elixir}
Macro.toString/1
を使えば式を文字列で取得できる。
iex> Macro.to_string(quote do: sum(1, 2 + 3, 4))
"sum(1, 2 + 3, 4)"
Unquoting
Quote
で式の構造を見ることができるが、場合によっては展開して欲しくない部分もあるかもしれない。以下の例を見てみる。
iex> number = 13
iex> Macro.to_string(quote do: 11 + number)
"11 + number"
- numberがそのままstringとして扱われていて、欲しい結果ではない。numberに値を注入するためには
unquote
を使う。
iex> number = 13
iex> Macro.to_string(quote do: 11 + unquote(number))
"11 + 13"
- さきほどとは異なり、
unquote
で囲んだnumberは束縛されている値が表示された。
unquote
は関数名にも適用できる。
iex> fun = :hello
iex> Macro.to_string(quote do: unquote(fun)(:world))
"hello(:world)"
fun
はhello/1
で展開された。
- Listの中に新しい要素を追加したい場合を考えてみる。
iex> inner = [3, 4, 5]
iex> Macro.to_string(quote do: [1, 2, unquote(inner), 6])
"[1, 2, [3, 4, 5], 6]"
- これは期待した結果ではない。このような場合は
unquote_splicing
を使うとよい。
iex> inner = [3, 4, 5]
iex> Macro.to_string(quote do: [1, 2, unquote_splicing(inner), 6])
"[1, 2, 3, 4, 5, 6]"
Unquoting
はコードの中に別のコードを埋め込むことができ、マクロを書くときにとても便利なので覚えておこう。
Escaping
Macro.escape/1
を使っても展開できる。
iex> map = %{hello: :world}
iex> Macro.escape(map)
{:%{}, [], [hello: :world]}
- マクロは
quoted expressions
を受け取りquoted expressions
を返す必要がある。大事なのはexpression
とvalue
を区別することである。integerやatom、stringといったようなvalueはquoted expressions
が自分自身の値だが、mapのような値は変換される必要がある。
- ちょっと訳が怪しいけど。。。おそらく以下のように
quote
をかけるとquoted expressions
が返るものと自身の値が返るもので違いがあるので気をつけろということかな。
iex> quote do: %{1=> 2}
{:%{}, [], [{1, 2}]}
iex> quote do: :hello
:hello