引用Elixir中的函数名称

时间:2017-03-13 01:03:14

标签: function macros elixir quote

我现在正在学习Elixir,我对quoteunquote感到困惑。 以下是使用macro创建具有动态名称的函数的方法:

defmacro create_fun(n) do
  quote do: def unquote(:"times_#{n}")(a), do: a * 4
end

例如,如果我将times_6作为宏参数传递,则会创建函数6

现在我不明白:这里我们取消引用原子:"times_#{n}"。 Elixir文档说,当你引用一个原子时,它会返回一个原子。因此,当我取消引用一个原子时,我也应该将这个原子带回来。这是真的:

iex(15)> Macro.to_string quote do: unquote(:"times_6")
":times_6"

但是在引用之后立即使用()给出了这个:

iex(14)> Macro.to_string quote do: unquote(:"times_6")()
"times_6()"

带圆括号的原子突然变成原子。如果我将unquote(:"times_6")替换为:"times_6"则不起作用:

iex(4)> Macro.to_string quote do: :"times_6"()
** (SyntaxError) iex:4: syntax error before: '('

拜托,发生了什么,我没有得到它

1 个答案:

答案 0 :(得分:4)

这就是quote& unquote在Elixir

中实施

来自Elixir Metaprogramming Guide

  

Elixir程序的构建块是一个有三个的元组   元素。例如,表示函数调用sum(1, 2, 3)   内部为:

iex> quote do: sum(1, 2, 3)
{:sum, [], [1, 2, 3]}
     

第一个元素是函数名称,第二个元素是关键字列表   包含元数据,第三个是参数列表。

模块和方法名称在内部表示为elixir中的atoms。直接查看调用unquote(:"hello")unquote(:"hello")()时生成的基础elixir数据可能有助于明确这一点:

iex(27)> quote do: unquote(:"hello")   
:hello

iex(28)> quote do: unquote(:"hello")() 
{:hello, [], []}

第一个只返回一个原子而第二个返回一个 Elixir数据结构(一个由3个元素组成的元组),它代表一个带有0个参数的hello方法的函数调用。 unquote(:"hello")()转换为hello(),然后将其用作方法。