Dlaczego Elixir raportuje UndefinedFunctionError
podczas wywoływania makra przy użyciu składni Module.macroName
w pliku .exs
? Wydaje mi się, że mogę wywołać makro tylko wtedy, gdy mam inną funkcję, która wywołuje makro i wywołuję funkcję zamiast makra.Eliksir - wywoływanie/wywoływanie makr - UndefinedFunctionError
Poniższy kod demonstruje to:
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
Wyjście
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
Przykład Elixir documentation wykorzystuje iex
, zamiast dzwonić makro w pliku .exs
. Nawet powyżej kodu, jeśli usuniemy połączenia do Sample.doIt
i załadujemy je w iex
, a następnie zadzwonimy pod numer Sample.doIt
działa dobrze.
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)>
Gdy próbuję require Sample
w moim pliku powyżej, jak poniżej
defmodule Sample
... rest of stuff as shown above ...
end
require Sample
Sample.doFunc "Hello World via Function"
Sample.doIt "Hello World from Macro!"
mi się błąd
** (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
Tutaj również zdefiniowałeś funkcję 'run' w innym module, aby użyć' Sample.doIt' - czy jest to jedyny sposób użycia makra - wywołaj go przez inną funkcję, która jest zawarta w Module –
być ograniczeniem kompilatora. Jak informuje błąd - nie można używać makr z modułu w tym samym kontekście, w którym moduł jest zdefiniowany. Zgaduję, że ma to związek z tym, jak kompilator zamawia rzeczy do kompilacji. –
Tak, dokładnie. Makra są rozszerzane w czasie kompilacji, więc gdy parsujemy 'defmodule Foo', a następnie' Foo.some_macro', nadal nie skompilowaliśmy 'Foo', więc nie mamy pojęcia, jak rozwinąć makro. –