function - 如何在 Elixir 中动态调用运算符

标签 function dynamic macros operator-keyword elixir

我正在阅读 Dave 即将出版的关于 Elixir 的书,在一个练习中,我想动态构造一个对 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)

最佳答案

您可以只使用 Erlang 之一:

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

我们知道这很令人困惑,我们正在研究使其更明确或更透明的方法。

更新:从 Elixir 1.0 开始,您可以直接发送到内核( apply Kernel, :+, [1, 2] ),甚至可以使用 OP 首次尝试的语法( &Kernel.+/2 )。

关于function - 如何在 Elixir 中动态调用运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21071424/

相关文章:

ios - 下载图像时调整 UITableViewCell 高度

c# - 如何克隆 ExpandoObject

c - gnu 库 C 中的 libc_hidden_​​proto 宏

sql - 为什么我的函数返回逗号分隔列表而不是行 (SQL Server)?

matlab - 将函数传递给 arrayfun

c - 在C中写入结构双向链表中的字符串

c - 如何消除一个多余的宏参数

带有两个选择语句的 PostgreSQLFunction

javascript - 如何通过单击按钮更改整个网站的字体和背景颜色

c - 有没有办法用 MSVC 编译器输出定义宏的有效列表?