Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to “splat” the function arguments for dynamically created function

I am generating some functions in the module:

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

The issue is the generated function obviously accepts one single argument, namely a list of size 2:

▶ M.__info__(:functions) 
#⇒ [do_it: 1]

The goal is to dynamically declare the function accepting two arguments. In ruby terminology, it would be to unsplat argument list.

Is there a possibility to accomplish this without pattern matching the resulting AST for {:do_it, blah, [[ list of arguments ]]} and flattening the list manually?

like image 707
Aleksei Matiushkin Avatar asked Jul 20 '26 00:07

Aleksei Matiushkin


1 Answers

You can use Kernel.SpecialForms.unquote_splicing/1 to "splice" in the args list:

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
iex(1)> M.__info__(:functions)
[do_it: 2, do_it: 3]
like image 193
Dogbert Avatar answered Jul 22 '26 17:07

Dogbert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!