13
votes

refer this post: How to create a dynamic function name using Elixir macro?.

The post above asked how to use macro to generate function without arguments, but I wonder how to generate functions with some arguments ?

assume there is a macro warp, I could just write code like:

warp fun, [args], :ok

and then it generate code like:

fun(args), do: :ok
2
I's hard enough to find docs about ´unquote_splicing´. The title change may help future googlers like me.nicooga

2 Answers

16
votes

If you want to generate a dynamic list of arguments, you need to use unquote_splicing, like this:

defmacro warp(name, argument_names, code) do
  quote do
    def unquote(name)(unquote_splicing(argument_names)) do
      unquote(code)
    end
  end
end

Then later:

warp :foo, [a, b], {:ok, a, b}

which generates:

def foo(a, b), do: {:ok, a, b}

if you call that it will produce:

foo(1, 2)
# {:ok, 1, 2}

You can also define the macro like this without unquote_splicing and just pass down the combined name and arguments to def:

defmacro warp(name_and_args, do: code) do
  quote do
    def unquote(name_and_args) do
      unquote(code)
    end
  end
end

This means you need to invoke warp like you would invoke def, for example:

warp foo(a, b), do: {:ok, a, b}
1
votes

Here's a very simple example:

defmodule SomeMacro do
  defmacro warp(name, status) do
    quote do
      def unquote(name)(args) do
        {unquote(status), Enum.join(args, " - ")}
      end
    end
  end
end

defmodule SomeModule do
  require SomeMacro
  SomeMacro.warp :something, :ok
end

And if you run it in IEX like this:

iex(1)> SomeModule.something([1,2,3])
{:ok, "1 - 2 - 3"}

iex(2)> SomeModule.something(["one", "two", "three"])
{:ok, "one - two - three"}

👍