如何"splat"动态创建函数的函数参数

Ale*_*kin 3 macros metaprogramming elixir

我在模块中生成一些函数:

defmodule M do
  funs = [do_it: [:arg1, :arg2]]

  Enum.each(funs, fn {name, args} ->
    args = Enum.map(args, & {&1, [], Elixir})
    def unquote(name)(unquote(args)),
      do: IO.inspect(unquote(args))
  end)
end
Run Code Online (Sandbox Code Playgroud)

问题是生成的函数显然接受一个参数,即大小为2的列表:

? M.__info__(:functions) 
#? [do_it: 1]
Run Code Online (Sandbox Code Playgroud)

目标是动态声明接受两个参数的函数.在ruby术语中,它将是unsplat参数列表.

是否有可能在没有模式匹配生成的AST {:do_it, blah, [[ list of arguments ]]}并手动展平列表的情况下完成此操作?

Dog*_*ert 6

您可以使用列表Kernel.SpecialForms.unquote_splicing/1中的"拼接" args:

defmodule M do
  funs = [do_it: [:arg1, :arg2], do_it: [:arg1, :arg2, :arg3]]

  Enum.each(funs, fn {name, args} ->
    def unquote(name)(unquote_splicing(args)), do: :ok
  end)
end
Run Code Online (Sandbox Code Playgroud)
iex(1)> M.__info__(:functions)
[do_it: 2, do_it: 3]
Run Code Online (Sandbox Code Playgroud)