【问题标题】:How to write a DSL that creates a function with arguments?如何编写一个 DSL 来创建一个带参数的函数?
【发布时间】:2018-06-10 03:05:19
【问题描述】:

我想定义一个宏,以便我可以将do 块传递给它,并让宏创建一个调用该块的函数,带有参数。我遇到了鸡和蛋的问题,因为下面的代码抱怨 name 没有定义。

defmodule MyMacro do
  defmacro greet(do: block) do
    quote do
      def hello(name), do: unquote(block)
    end
  end
end

defmodule Test do
  import MyMacro
  greet do
    IO.puts("Hello, #{name}!")
  end
end

尝试编译此代码会导致:

(CompileError) iex:6: undefined function name/0
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5

据我了解,这甚至在它到达我的宏之前就爆炸了,因为 elixir 在调用我的宏之前尝试为 do 块生成一个 AST,但 name 是未定义的。

我的目标是在编译 DSL 后能够调用Test.hello("world")。 Elixir 有可能吗?

【问题讨论】:

    标签: macros elixir metaprogramming dsl


    【解决方案1】:

    Elixir 的宏是hygienic,因此如果您在宏的quote 中声明变量,调用者将无法使用该变量。您可以通过使用var! 包装变量声明来禁用此功能:

    quote do
      def hello(var!(name)), do: unquote(block)
    end
    

    【讨论】:

    • 谢谢你,我把头发拉出来了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多