【问题标题】:How to define a function based on a previously defined function on a module?如何根据模块上先前定义的函数定义函数?
【发布时间】:2014-07-21 12:57:40
【问题描述】:

我正在尝试基于模块上已定义的函数来定义函数。

我想做这样的事情:

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

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

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

Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
  args = Enum.map(0..arity-1, fn i -> "arg_#{i}" end)
      quoted = quote do
  def unquote(func_name)(unquote_splicing(args)) do
     ....

但我仍然没有成功。有人对我如何得到这个有任何想法吗? :)

【问题讨论】:

    标签: metaprogramming elixir


    【解决方案1】:

    你可以这样做:

    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 的定义。初始代码的问题在于,当您映射并引用定义时,您从未评估过那些引用的表达式,因此它们没有被编译为模块的一部分。

    【讨论】:

      【解决方案2】:

      其实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
      

      【讨论】:

      • 不错!对我来说仍然有一个问题是如何定义一个具有 arity 参数数量的函数。如果 arity = 3 -> def func_name(arg1, arg2, arg3) ...
      • 这是一个动态创建 n-arity 函数的要点,该函数返回一个包含所有参数的元组:gist.github.com/sasa1977/ea3488e1c285ad527bc0
      • 对不起,我误解了你的问题。看来可以使用 Code.string_to_quoted。我已经更新了要点。
      • 哈哈哈,不用了。我的奖励是我也学到了一些东西。你的问题促使我更深入地研究文档,所以我发现了 Code.string_to_quoted :-)
      • @Eduardo 似乎最近以 Macro.var/1 的形式添加了一个使解决方案更清晰的内容。我再次更新了要点。
      猜你喜欢
      • 1970-01-01
      • 2017-10-16
      • 2019-04-23
      • 2015-10-23
      • 2023-02-05
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 2014-12-06
      相关资源
      最近更新 更多