繁体   English   中英

灵药中的宏扩展:如何使用另一个宏定义2个宏?

[英]Macro expansion in elixir: how to define 2 macros with one using the other?

我在elixir中试验Macros。 因此,我即将展示的代码当然应该用简单的函数完成,但是......我正在试验!

我想定义2个宏(A和B)并使A使用B来试验宏扩展。 当我使用A时,我收到一个编译错误,说明函数 B 未定义

这是代码:

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

我(错)理解事物的方式:

  1. 通过要求MyMacros,模块MyModule应该知道两个宏的存在。 因此我应该可以使用任何宏。
  2. 当在MyModule中展开print_hashes_around时,编译器应该发现print_expr也是一个宏。 因此,应该进行另一次扩张。
  3. 似乎发生的事情是第二次扩张不会发生。 因此,编译器会查找不存在的函数定义。

我对吗 ?

正如松弛所示,将print_expr添加到MyMacros.前缀MyMacros. 解决它。 我还是不明白为什么。 MyModule需要MyMacros因此两个宏都应该是已知的并且可以扩展...当我查看unless的定义时,它使用if ,而不是Kernel.if

通过要求MyMacros,模块MyModule应该知道两个宏的存在。 因此我应该可以使用任何宏。

误会就在这里。 :) require只使模块可用于编译器,它不会导入模块函数。 如果您使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM