Elixir Metaprogramming:将函数调用列表注入函数体

时间:2017-06-29 10:55:27

标签: elixir metaprogramming

我有一个格式为{:task, function_name, description}的元组列表,我想生成一个调用元组中定义的函数来覆盖值的函数。

我生成的函数应如下所示:

def run(val) do
  val = do_something(val)
  val = do_something_else(val)
  ...

  val
end

这是我目前的代码:

  defmacro __before_compile__(env) do

    steps =  Module.get_attribute(env.module, :steps) |> Enum.reverse

    iteration = Enum.map steps, fn {:task, func, _} ->
      quote do
        val = unquote(func)(val)
      end
    end

    ast = quote do
      def run(val) do

        unquote(iteration)

        val
      end
    end

    ast
  end

但是这会产生以下功能:

def(run(val)) do
  [val = it_adds_five(val), val = it_adds_ten(val)]
  val
end

如您所见,我的函数调用位于列表中,只应用了最后一个函数调用。当我将值2传递给run函数时,我会返回12

1 个答案:

答案 0 :(得分:2)

您可以使用Kernel.SpecialForms.unquote_splicing/1代替Kernel.SpecialForms.unquote/1来拼接"拼接"在AST节点列表中。

更改:

def run(val) do
  unquote(iteration)
  val
end

def run(val) do
  unquote_splicing(iteration)
  val
end

生成此AST:

def(run(val)) do
  val = bar(val)
  val = foo(val)
  val
end

@steps [
  {:task, :foo, ""},
  {:task, :bar, ""},
]