【问题标题】:Is there an easy way to see what an Elixir macro expands to?有没有一种简单的方法可以查看 Elixir 宏扩展的内容?
【发布时间】:2016-02-04 15:22:05
【问题描述】:

在过去 18 个月左右的时间里,Elixir 一直是我的首选语言,但我有时会发现“没有魔法”的口头禅(尤其是引用 Phoenix vs Rails)和宏的使用之间存在矛盾。

虽然我现在在使用没有宏的语言时会想念宏,但我仍然希望更容易看到它们实际在做什么。我的某些部分总是想拉开 DSL 的帷幕,看看真正的代码。

有没有一种简单的方法来扩展宏并查看它们生成的代码(可能通过 IEx),这样我就不必在脑海中挖掘 defmacro 层来尝试将其拼凑起来。

【问题讨论】:

    标签: macros elixir


    【解决方案1】:

    您可以使用 Macro.expand/2 扩展宏

    iex> Macro.expand((quote do: (if true, do: 1)), __ENV__)
    {:case, [optimize_boolean: true],
     [true,
      [do: [{:->, [],
         [[{:when, [],
            [{:x, [counter: 6], Kernel},
             {:in, [context: Kernel, import: Kernel],
              [{:x, [counter: 6], Kernel}, [false, nil]]}]}], nil]},
        {:->, [], [[{:_, [], Kernel}], 1]}]]]}
    

    然后您可以使用Macro.to_string/2 将输出作为字符串而不是AST:

    iex> Macro.expand((quote do: (if true, do: 1)), __ENV__) |> Macro.to_string()
    "case(true) do\n  x when x in [false, nil] ->\n    nil\n  _ ->\n    1\nend"
    

    然后您可以使用IO.puts/2 将字符串打印到终端:

    iex> Macro.expand((quote do: (if true, do: 1)), __ENV__) |> Macro.to_string() |> IO.puts()
    case(true) do
      x when x in [false, nil] ->
        nil
      _ ->
        1
    end
    

    【讨论】:

    • 如果我的宏在一个模块中,但我仍然想看看它扩展成这样,我该怎么做?
    【解决方案2】:

    试试 Chris McCord 的这个技巧:

    your_ast |> Macro.expand(__ENV__) |> Macro.to_string |> IO.puts
    

    【讨论】:

      猜你喜欢
      • 2012-07-26
      • 2011-11-03
      • 1970-01-01
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      • 2012-04-04
      • 1970-01-01
      • 2020-08-15
      相关资源
      最近更新 更多