我正在 Elixir 中尝试宏。因此,我要展示的代码当然应该使用简单的函数来完成,但是..我正在尝试!
我想定义2个宏(A和B)并让A使用B来试验宏扩展。
当我使用 A 时,我收到一个编译错误,指出function B is 不明确的.
这是代码:
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")
这是编译错误:
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
我(错误)理解事物的方式:
- 通过要求 MyMacros,模块 MyModule 应该知道这两个宏的存在。因此我应该能够使用任何宏。
- 当 print_hashes_around 在 MyModule 中展开时,编译器应该发现 print_expr 也是一个宏。因此,应该会发生另一次扩张。
- 似乎发生的是第二次扩张并没有发生。因此,编译器会查找不存在的函数定义。
我对吗 ?
正如 slack 中所建议的,前缀print_expr
with MyMacros.
修复它。我还是不明白为什么。MyModule
需要MyMacros
所以两个宏都应该是已知的并且可扩展的......当我查看的定义时unless
, 它用if
, not Kernel.if
.
通过要求 MyMacros,模块 MyModule 应该知道这两个宏的存在。因此我应该能够使用任何宏。
误会就在这里。 :)require
只使模块可供编译器使用,而不是import模块功能。如果你用过import MyModule
然后就可以了。
但是,最好通过在模块名称前加上前缀来解决该问题,因为这样您就可以允许开发人员使用您的代码显式地使用您的宏(使用require
)或通过导入它们。
另一种选择是避免多次宏调用,如下所示:
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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)