在 Elixir 中引用函数名

Quote function name in Elixir

我现在正在学习 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 文档说当你引用一个原子时它 returns 一个原子。所以当我取消引用一个原子时,我也应该取回这个原子。这是真的:

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

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

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

带括号的原子突然变成了非原子。如果我用 :"times_6" 替换 unquote(:"times_6") 它不起作用:

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

拜托,这是怎么回事,我不明白

这就是 quoteunquote 在 Elixir 中的实现方式

来自Elixir Metaprogramming Guide:

The building block of an Elixir program is a tuple with three elements. For example, the function call sum(1, 2, 3) is represented internally as:

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

The first element is the function name, the second is a keyword list containing metadata and the third is the arguments list.


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

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

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

第一个只是returns一个原子,而第二个returns一个Elixir数据结构(一个由3个元素组成的元组)代表一个使用 0 个参数调用 hello 方法。 unquote(:"hello")() 转换为 hello() 然后用作方法。