Elixir 中的宏扩展:如何定义两个宏,一个使用另一个宏?

2024-01-31

我正在 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

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

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

我对吗 ?

正如 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(使用前将#替换为@)

Elixir 中的宏扩展:如何定义两个宏,一个使用另一个宏? 的相关文章

  • AIRFLOW:在 jinja 模板中为 {{ds}} 使用 .replace() 或relativedelta()

    我的目标是根据气流宏变量 ds 返回上个月的第一天并使用它 例如在 Hive 操作符中 例如 对于 ds 2020 05 09 我预计返回 2020 04 01 我找到并尝试的解决方案是 SET hivevar LAST MONTH ds
  • GCC/CLANG 与 MSVC 的预处理器之间有何差异?

    以下预处理器宏 通常的嫌疑人 测试空参数列表并计算参数数量 在 gcc clang 上运行时没有警告 但在 Microsoft VisualC 上失败 IS EMPTY returns nothing if the parameter li
  • Ecto - 验证关联模型的存在

    如何验证 Ecto 中是否存在关联模型 schema foo do has many bar Bar timestamps end required fields w bar invalid 有办法这样做吗 并验证这些字段的最小 最大数量
  • 无与伦比的括号宏怪异

    根据 C99 规则预处理以下 3 行的正确输出是什么 define y x x define x a y a x 1 x 2 顺便说一句 linux 下的 cpp 会产生错误消息 但我不明白为什么答案不简单 1 2 假设 cpp 是正确的而
  • GenServer 正常关闭

    我使用 GenServer 编写了一个 Elixir 应用程序 该应用程序在启动时启动外部应用程序 然后将其关闭 并在退出时进行其他清理 我在中添加了启动功能init 1 https hexdocs pm elixir GenServer
  • 以 at (@) 符号为前缀的 Objective-C 宏的含义

    ReactiveCocoa 框架利用weakify and strongify宏 两者前面都有一个 符号 这是一个例子 从这个file https github com ReactiveCocoa ReactiveCocoa blob fd
  • Jupyter (iPython) 笔记本中的 Latex 宏未由 github 渲染

    我的 Jupyter 笔记本 ipynb 中有一个 Markdown 单元 其中包含以下内容 newcommand paren 1 left 1 right paren beta 2 该文件位于 Github 存储库中 LaTex 宏应用程
  • F# 类型提供程序与 Lisp 宏

    我一直在阅读有关 F 3 0 类型提供程序的内容 例如here http msdn microsoft com en us library hh156509 aspx 并且它们似乎基于一种编译时代码生成 在这方面我想知道它们与 Lisp 宏
  • Phoenix 中的 web/static 和 priv/static 有什么区别?

    我对长生不老药和凤凰是新手 现在我在凤凰城的静态资产方面遇到了麻烦 我想在我的页面中添加一个js文件 我在我的模板中添加以下代码 js test js gt gt 然后创建一个js文件web static js test js 但是 我收到
  • Scala 宏的位置怎么了?

    我试图获取宏参数的原始输入字符串 但返回的位置似乎有点偏离 考虑这个宏 例如 object M import scala reflect macros Context import language experimental macros
  • 使用 Ansible 将二进制文件添加到 PATH

    我正在尝试安装Kiex https github com taylor kiex版本管理器Elixir http elixir lang org install html使用 Ansible 的编程语言 这些是我为此使用的戏剧 name K
  • 实现只有一个居民的类型的价值

    感谢 MilesSabin 的answer https stackoverflow com a 32157259 867671我可以编写类型级别的斐波那契序列 sealed trait Digit case object Zero exte
  • 是否可以在 C 中自动生成的变量名中使用 __LINE__ ?

    为了避免重复 我想使用 LINE 在自动生成的变量名称中 define ROUTE path impl char k impl LINE route path impl 但它始终被视为普通字符串 LINE 即使我将其定义如下 我也无法得到我
  • 在 clojure 中,使用递归实现宏时如何进行代码模板化

    我正在尝试实现一个宏 以递归地将中缀列表转换为前缀列表 我遇到一个问题如下 this works defmacro recursive infix form list second form first form if not seq nt
  • 设置、让、宏、坚果

    我正在尝试从 html 内容构建一个快速目录 为了简短起见 代码非常简单 defn toc content doseq i take 5 iterate inc 1 let h str h i println content h where
  • 用于将具有相同前缀的所有变量的值相加的 SPSS 语法

    我想知道是否有一种方法可以让 SPSS 将具有相同前缀的所有变量相加 例如 我有名为MFQAP 1 MFQAP 2 MFQAP 3等等 有没有办法告诉SPSS将所有以以下开头的变量相加MFQAP 我知道我可以告诉 SPSS 将所有变量相加M
  • 使用 Elixir 生成首字母头像 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在开发 Elixir 并希望提供头像服务 如果用户没有头像 可以制作一个带有他们姓名首字母缩写的头像 如下所示 我真的不知道从哪里
  • Google Test 宏似乎不适用于 Lambda 函数

    所以 我有以下代码 无论 Interpolator 类的细节是什么 在这种情况下它都不应该抛出异常 这就是我想要测试的 TEST errorhandlingInterpolator toolargeInput const size t nu
  • 类型不匹配插入:binary_id 与 Ecto 变更集

    我有一张桌子applications有外键user id这是一个 Postgresuuid 我在我的web ex primary key id binary id autogenerate true foreign key type bin
  • PHP 内部:TSRMLS_FETCH 如何工作?

    PHP 内部结构是怎样的TSRMLS FETCH宏发挥作用吗 Per the PHP手册 http php net manual en internals2 memory tsrm php 在开发扩展时 包含 tsrm ls is unde

随机推荐