Macro extension in elixir: how to define 2 macros using one another?

I am experimenting with macros in an elixir. Therefore, the code that I'm going to show must be executed using simple functions, but .. I'm experimenting!

I want to define 2 macros (A and B) and make A use B to experiment with macro expansion. When I use A, I get a compilation error saying that function B is undefined .

Here is the code:

defmodule MyMacros do defmacro print_expr(expr) do quote do IO.puts(unquote(expr)) end end defmacro print_hashes_around(expr) do quote do IO.puts "###" print_expr(unquote(expr)) IO.puts "###" end end end defmodule MyModule do require MyMacros def my_print(expr) do MyMacros.print_hashes_around(expr) end end MyModule.my_print("hello world") 

And here is the compilation:

 macro_test.exs:17: warning: redefining module MyModule ** (CompileError) macro_test.exs:21: function print_expr/1 undefined (stdlib) lists.erl:1336: :lists.foreach/2 macro_test.exs:17: (file) (elixir) lib/code.ex:307: Code.require_file/2 

How I (incorrectly) understand things:

  • When using MyMacros, the MyModule module must know the presence of both macros. Therefore, I should be able to use any macros.
  • When print_hashes_around expands in MyModule, the compiler should detect that print_expr is also a macro. Therefore, another extension must occur.
  • Something similar to the fact that the second extension does not occur. Therefore, the compiler is looking for a definition of a function that does not exist.

I'm right?

As suggested by slack, the print_expr prefix print_expr with MyMacros. corrects him. I still don’t understand why. MyModule requires MyMacros , so both macros must be known and extensible ... When I look at the unless definition, it uses if , not Kernel.if .

+7
macros elixir
source share
1 answer

When using MyMacros, the MyModule module must know the presence of both macros. Therefore, I should be able to use any macros.

Misunderstanding here. :) require only makes the module available to the compiler, it does not import module functions. If you used import MyModule then this will work.

However, it would be better to fix the problem by specifying the module name first, because then you allow developers to use your code to explicitly use your macros (using require ) or by importing them.

Another option is to avoid several call macros, such as:

 defmodule MyMacros do defmacro print_expr(expr) do quoted_print_expr(expr) end defmacro print_hashes_around(expr) do quote do IO.puts "###" unquote(quoted_print_expr(expr)) IO.puts "###" end end defp quoted_print_expr(expr) do quote do IO.puts(unquote(expr)) end end end 
+9
source share

All Articles