如何动态调用Elixir中的运算符

 踢出个未来为我鼓掌 发布于 2023-02-04 13:17

我工作过戴维的即将出版的新书在花好月圆我的方式,并且在一个锻炼,我想动态构造函数引用Kernel.+/2,Kernel.-/2等等,基于一个字符串的一个字符的内容'+','-'等等.

基于另一个SO问题,我希望能够调用apply/3传递内核,:+和这两个数字:

apply(Kernel, :+, [5, 7])

这不起作用,因为(如果我理解的话)Kernel.+/2是一个宏,而不是一个函数.我查找了源代码,并根据+其定义__op__,我可以从iex以下地址调用它:

__op__(:+, 5, 7)

这有效,直到我将:+放入变量:

iex(17)> h = list_to_atom('+')
:+
iex(18)> __op__(h, 5, 7)
** (CompileError) iex:18: undefined function __op__/3
    src/elixir.erl:151: :elixir.quoted_to_erl/3
    src/elixir.erl:134: :elixir.eval_forms/4

而且我猜测没有办法打电话__op__使用apply/3.

当然,蛮力方法可以完成工作.

  defp _fn(?+), do: &Kernel.+/2
  defp _fn(?-), do: &Kernel.-/2
  defp _fn(?*), do: &Kernel.*/2
# defp _fn(?/), do: &Kernel.//2   # Nope, guess again
  defp _fn(?/), do: &div/2        # or &(&1 / &2) or ("#{div &1, &2} remainder #{rem &1, &2}")

但是有更简洁和动态的东西吗?


JoséValim在下面给出了答案.这是上下文中的代码:

  def calculate(str) do 
    {x, op, y} = _parse(str, {0, :op, 0})
    apply :erlang, list_to_atom(op), [x, y]
  end

  defp _parse([]     , acc      )                 , do: acc
  defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0})
  defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, [h], 0})
  defp _parse([_ | t], acc      )                 , do: _parse(t, acc)

José Valim.. 9

你可以使用Erlang:

apply :erlang, :+, [1,2]

我们意识到这是令人困惑的,我们正在研究制定或更明确或更透明的方法.

更新:自Elixir 1.0以来,您可以直接调度到Kernel(apply Kernel, :+, [1, 2]),甚至可以使用OP首先尝试的语法(&Kernel.+/2).

1 个回答
  • 你可以使用Erlang:

    apply :erlang, :+, [1,2]
    

    我们意识到这是令人困惑的,我们正在研究制定或更明确或更透明的方法.

    更新:自Elixir 1.0以来,您可以直接调度到Kernel(apply Kernel, :+, [1, 2]),甚至可以使用OP首先尝试的语法(&Kernel.+/2).

    2023-02-04 13:20 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有