Почему 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
Здесь вы также определили функцию 'run' в другом модуле для использования' Sample.doIt' - это единственный способ использовать макрос - вызвать его с помощью другой функции, которая заключена в модуль –
. для ограничения компилятора. Как говорится в ошибке: вы не можете использовать макросы из модуля в том же контексте, где определен модуль. Я предполагаю, что это связано с тем, как компилятор заказывает вещи для компиляции. –
Да, точно. Макросы расширяются во время компиляции, поэтому, когда мы анализируем 'defmodule Foo', за которым следует' Foo.some_macro', мы до сих пор не скомпилировали 'Foo', поэтому мы понятия не имеем, как развернуть макрос. –