Elixir macros and bind_quoted

前端 未结 2 661
悲哀的现实
悲哀的现实 2021-02-08 17:49

I have a macro that defines a module like so.

defmodule Bar do
  def bar do
    IO.puts \"I am #{inspect __MODULE__}\"
  end
end

defmodule MacroFun do

  defmac         


        
相关标签:
2条回答
  • 2021-02-08 18:27

    With this code you will see the correct values used to create the modules:

    require Logger
    
    defmodule Bar do
      def bar do
        IO.puts "I am #{inspect __MODULE__}"
      end
    end
    
    defmodule MacroFun do
    
      defmacro define_module(name) do
        quote do
          Logger.debug("#{inspect unquote(name)}")
          defmodule unquote(name) do
            import Bar
            Logger.debug("#{inspect unquote(name)}")
            def foo do
              bar
              IO.puts "I am #{inspect __MODULE__}"
            end
          end
        end
      end
    
      defmacro define_module2(name) do
        quote bind_quoted: [name: name] do
          defmodule name do
            import Bar
            Logger.debug("#{inspect name}")
            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
      def run2 do
        MacroFun.define_module2 Foo2
        Foo2.foo
      end
    
    end
    
    Runner.run
    Runner.run2
    

    Output:

    [warn]  Foo
    [warn]  Runner.Foo
    I am Bar
    I am Runner.Foo
    
    [warn]  Foo2
    I am Bar
    I am Foo2
    
    0 讨论(0)
  • 2021-02-08 18:42

    I think that's because the place where you are unquoting (binding) the variable name.

    In the first case, you are unquoting the variable name when creating a module, thus binding the variable at that moment would require to check for context (check if the code is inside another module, for example). So, you get your current atom plus the appropriate context: Runner.Foo.

    In the second case, you are unquoting the variable name before it's placed in a context, therefore its value will not change and it'll be the atom Foo (no context).

    0 讨论(0)
提交回复
热议问题