如何根据模块上先前定义的函数定义函数?

时间:2014-06-01 05:38:03

标签: metaprogramming elixir

我试图根据模块上已经定义的函数定义一个函数。

我想做这样的事情:

defmodule A do
  def my_func(pid, arg1, arg2) do
    send pid, "Do Something"
  end
end

在定义my_func之后,我想定义调用my_func(arg1, arg2)的{​​{1}}来传递一个pid,例如我将从一个pid池中获取。

我的第一次尝试是使用@on_definition,但我没有成功。然后我尝试在模块中执行此操作:

my_func

但我仍然没有成功。任何人都知道如何得到这个? :)

2 个答案:

答案 0 :(得分:3)

你可以这样做:

defmodule Test do
  def my_func(pid, arg1, arg2) do
    send pid, {arg1, arg2}
  end

  quoted = Enum.map Module.definitions_in(__MODULE__, :def), fn {func_name, _arity} ->
    quote do
      def unquote(func_name)(arg1, arg2) do
        pid = :some_pid
        unquote(func_name)(pid, arg1, arg2)
      end
    end
  end
  Module.eval_quoted(__MODULE__, quoted)

  Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
    IO.inspect {func_name, arity}
  end
end

如果您使用elixirc test.ex进行编译,则会看到它吐出my_func/2my_func/3的定义。初始代码的问题在于,当您映射并引用定义时,您从未评估过这些引用的表达式,因此它们不会被编译为模块的一部分。

答案 1 :(得分:3)

实际上,bitwalker的解决方案可以简化。您不需要引用并执行eval_quoted,因为def是一个直接注入AST的宏。所以这也会起作用:

defmodule Test do
  def my_func(pid, arg1, arg2) do
    send pid, {arg1, arg2}
  end

  Enum.map Module.definitions_in(__MODULE__, :def), fn {func_name, _arity} ->
    def unquote(func_name)(arg1, arg2) do
      pid = :some_pid
      unquote(func_name)(pid, arg1, arg2)
    end
  end

  Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
    IO.inspect {func_name, arity}
  end
end