Elixir - 调用/调用宏 - UndefinedFunctionError

Wan*_*ker 7 elixir

为什么Elixir 在使用文件中的语法UndefinedFunctionError调用宏时报告?我似乎只能调用宏,如果我有另一个调用宏的函数,我调用函数而不是宏.Module.macroName.exs

下面的代码演示了这个

defmodule Sample do
  defmacro doIt(expression) do
    quote do
      IO.puts unquote(expression)
    end
  end

  def doFunc(e), do: doIt(e)
end

Sample.doFunc "Hello World via Function" # Works fine
Sample.doIt "Hello World from Macro!" # Gives error
Run Code Online (Sandbox Code Playgroud)

产量

Hello World via Function
** (UndefinedFunctionError) undefined function: Sample.doIt/1
    Sample.doIt("Hello World from Macro!")
    (elixir) lib/code.ex:307: Code.require_file/2
Run Code Online (Sandbox Code Playgroud)

该药剂文档示例使用iex,而不是在调用宏.exs文件.即使是上面的代码,如果我们删除调用Sample.doIt 并加载它iex,然后调用Sample.doIt工作正常.

E:\elixir>iex hello.exs
Hello World via Function
Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> require Sample
nil
iex(2)> Sample.doIt "Hello"
Hello
:ok
iex(3)>
Run Code Online (Sandbox Code Playgroud)

如果我尝试require Sample在上面的文件中,如下所示

defmodule Sample
  ... rest of stuff as shown above ...
end

require Sample

Sample.doFunc "Hello World via Function"
Sample.doIt "Hello World from Macro!"
Run Code Online (Sandbox Code Playgroud)

我收到错误

** (CompileError) hello.exs:11: module Sample is not loaded but was defined. This happens because you are trying to use a module in the same context it is defined. Try defining the module outside the context that requires it.
    (stdlib) lists.erl:1352: :lists.mapfoldl/3
    (stdlib) lists.erl:1353: :lists.mapfoldl/3
Run Code Online (Sandbox Code Playgroud)

Paw*_*rok 5

像往常一样,在使用宏之前需要一个模块来向编译器表明编译模块的顺序:

defmodule Other do
  def run do
    require Sample

    Sample.doFunc "Hello World via Function"
    Sample.doIt "Hello World from Macro!"
  end
end

Other.run # => Hello World via Function
          #    Hello World from Macro!
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是编译器的限制.正如错误所示 - 您无法在定义模块的同一上下文中使用来自模块的宏.我猜它与编译器如何命令编译的东西有关. (4认同)
  • 对,就是这样.宏是在编译时间,所以扩大了,当我们分析`defmodule Foo`其次是`Foo.some_macro`,我们还没有编译`Foo`,所以我们不知道如何扩展宏. (3认同)