cjb*_*aro 8 macros metaprogramming elixir
我有一个定义模块的宏.
defmodule Bar do
def bar do
IO.puts "I am #{inspect __MODULE__}"
end
end
defmodule MacroFun do
defmacro define_module(name) do
quote do
defmodule unquote(name) do
import Bar
def foo do
bar
IO.puts "I am #{inspect __MODULE__}"
end
end
end
end
end
defmodule Runner do
require MacroFun
def run do
MacroFun.define_module Foo
Foo.foo
end
end
Runner.run
Run Code Online (Sandbox Code Playgroud)
运行它的输出是:
I am Bar
I am Runner.Foo
Run Code Online (Sandbox Code Playgroud)
这是有道理的; MacroFun.define_module被调用,Runner.run因此模块被定义并因此嵌套在Runner模块下.
但是现在如果我MacroFun.define_module改为使用:bind_quoted选项:
defmacro define_module(name) do
quote bind_quoted: [name: name] do
defmodule name do
import Bar
def foo do
bar
IO.puts "I am #{inspect __MODULE__}"
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
输出现在变为:
I am Bar
I am Foo
Run Code Online (Sandbox Code Playgroud)
为什么??
我认为这是因为这个地方在那里你unquoting(绑定)变量name.
在第一种情况下,您name在创建模块时取消对变量的引用,因此在此时绑定变量需要检查上下文(例如,检查代码是否在另一个模块中).所以,你得到你当前的原子加上适当的上下文:Runner.Foo.
在第二种情况下,您在将变量name置于上下文之前对其进行取消引用,因此其值不会更改,它将是原子Foo(无上下文).