简体   繁体   English

为动态生成的宏加双引号

[英]Double unquoting for dynamically generated macros

Given the following: 给定以下内容:

  for fn_name <- [:foo, :bar, :baz] do
    defmacro unquote(fn_name)(do: inner) do
      fn_name = unquote(fn_name) # <--- Why?
      quote do
        IO.puts "#{unquote(fn_name)} called"
        unquote(inner)
      end
    end
  end

What's the reason for fn_name = unquote(fn_name) ? fn_name = unquote(fn_name)的原因是什么? If I omit this line, it's a compile error. 如果我省略此行,则为编译错误。 What's the reason for this "double" unquoting? 这种“双重”取消报价的原因是什么?

Let's simplify the example a little bit: 让我们稍微简化一下示例:

for fn_name <- [:foo, :bar, :baz] do
  defmacro unquote(fn_name)(do: inner) do
    fn_name = unquote(fn_name) # <--- Why?
    quote do
      {unquote(fn_name), unquote(inner)}
    end
  end
end

In the example above, because quote is returning a tuple with two unquoted elements, it is equivalent to: 在上面的示例中,因为quote返回带有两个未引用元素的元组,所以它等效于:

for fn_name <- [:foo, :bar, :baz] do
  defmacro unquote(fn_name)(do: inner) do
    fn_name = unquote(fn_name) # <--- Why?
    {fn_name, inner}
  end
end

Now it is easier to understand what happens if you don't unquote(fn_name) before: the variable fn_name simply wouldn't exist inside the macro definition. 现在,更容易理解如果您之前不unquote(fn_name)会发生什么:宏定义内根本就不存在变量fn_name Remember that all def s (def, defp, defmacro, etc) start a new variable scope, so if you want to use fn_name inside, you need to define it somehow. 请记住,所有def (def,defp,defmacro等)都会启动一个新的变量作用域,因此,如果要在内部使用fn_name,则需要以某种方式对其进行定义。

The other property we are seeing in this code is that Elixir will stop unquoting when it sees a quote . 我们在此代码中看到的另一个属性是Elixir在看到quote时将停止取消quote So in the quote above, unquote won't be unquoted when the macro is defined but rather when the macro is executed, which also explains why the variable is required to be defined inside the macro. 因此在上面的报价, unquote的宏定义,而是在执行宏,这也解释了为什么需要变量的宏内部被定义时,不会加引号。

It's because of Hygiene . 这是因为卫生

Elixir has the concept of macro hygiene . 长生不老药有宏观卫生学的概念。 Hygiene means that variables, imports, and aliases that you define in a macro do not leak into the caller's own definitions. 卫生意味着您在宏中定义的变量,导入和别名不会泄漏到调用者自己的定义中。

for fn_name <- [:foo, :bar, :baz] do
    defmacro unquote(fn_name)(do: inner) do
      fn_name = unquote(fn_name) # <-- This is macro's context
      quote do
        IO.puts "#{unquote(fn_name)} called" # <-- This is caller's context
        unquote(inner)
      end
    end
  end

You should read Hygiene Protects the Caller's Context from Chris McCord's Metaprogramming Elixir book 您应该从Chris McCord的Metaprogramming Elixir书中阅读“ 卫生保护呼叫者的上下文

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM