2015-08-08 3 views
6

Почему Elixir сообщает UndefinedFunctionError при вызове макроса с использованием Module.macroName синтаксиса в файле .exs? Кажется, я могу вызвать макрос, только если у меня есть другая функция, которая вызывает макрос, и я вызываю функцию вместо макроса.Elixir - Вызов/Вызов макросов - UndefinedFunctionError

Ниже код демонстрирует это:

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 

Выход

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 

Elixir documentation пример использует 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)> 

Если я пытаюсь 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!" 

Я получаю ошибку

** (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 

ответ

4

Как обычно вам нужно требовать модуль перед использованием его макросы для обозначения компилятору порядок составления модулей:

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! 
+0

Здесь вы также определили функцию 'run' в другом модуле для использования' Sample.doIt' - это единственный способ использовать макрос - вызвать его с помощью другой функции, которая заключена в модуль –

+3

. для ограничения компилятора. Как говорится в ошибке: вы не можете использовать макросы из модуля в том же контексте, где определен модуль. Я предполагаю, что это связано с тем, как компилятор заказывает вещи для компиляции. –

+3

Да, точно. Макросы расширяются во время компиляции, поэтому, когда мы анализируем 'defmodule Foo', за которым следует' Foo.some_macro', мы до сих пор не скомпилировали 'Foo', поэтому мы понятия не имеем, как развернуть макрос. –

Смежные вопросы