【问题标题】:Specify arity using only or except when importing function on Elixir在 Elixir 上导入函数时使用 only 或 except 指定arity
【发布时间】:2014-12-25 23:28:44
【问题描述】:

我正在研究 Elixir,当我在从模块导入函数时使用 onlyexcept 运算符时,我需要指定一个元数。为什么?

例如

import :math, only: [sqrt: 1]

import :math, except: [sin: 1, cos: 1]

【问题讨论】:

  • 因为这是 Elixir 独有的东西(据我所知),您可能应该从问题中删除 erlang 标签。

标签: functional-programming elixir


【解决方案1】:

在整个 Erlang 生态系统中,功能由名称 + 数量来标识。在大多数其他语言中,您可以按名称​​重载函数。换句话说,在 Erlang 世界中 foo/1(即 foo(one_arg))是一个完全不同于 foo/2 的函数(如 foo(one_arg, two_arg)),但在Python 或 Ruby “foo” 是完整的函数标识,可以使用灵活数量的参数调用它。

约定是将表示相同事物的函数命名为相同的名称,尤其是在递归定义的迭代函数的情况下,例如:

factorial(N) -> factorial(1, N).

factorial(A, 0) -> A;
factorial(A, N) -> factorial(A * N, N - 1).

注意有两个句点,这意味着这里有两个完全独立的定义。我们也可以这样写:

fac(N) -> sum(1, N).

sum(A, 0) -> A;
sum(A, N) -> sum(A * N, N - 1).

但是您会注意到,第二个版本在字符笔划方面的节省远远超过其语义卷积的影响——第二个版本的内部函数名称是彻头彻尾的谎言!

惯例是将相关函数命名为相同的东西,但实际上在 Erlang 生态系统中不允许通过 arity 重载函数。为了使这种重载可以接受,需要对编译为 Erlang 字节码的语言的编译器添加大量功能,而这将是对痛苦努力的毫无意义的浪费。目前的情况与我们可以在动态类型的函数式语言中获得的一样好(没有成为静态类型的函数式语言......这完全是另一个讨论)。

最终结果是您必须准确地指定要导入的函数,无论是在 Erlang 中还是在 Elixir 中,这意味着通过名称 + arity 来识别它。认识到通用约定是对执行相同操作但具有不同参数计数的函数使用相同的名称(通常只需编写级联的柯里化定义来包含通用默认值),Elixir 提供了一种按组包含函数而不是枚举的快捷方式他们。

因此,当您 import :math, only: [sqrt: 1] 时,您只需要使用 math:sqrt/1 并忽略模块的其余部分(如果有 math:sqrt/2,您会忽略它)。当你import :math, except: [sin: 1, cos: 1] 时,你会带走所有东西但是 math:sin/1math:cos/1(如果有math:sin/2 你会带走它)。 name + arity 是一个独特的身份。想象一下可用功能的大型 KV 存储。键是{module, func, arity},这意味着它们是系统的原子值。如果您对 Erlang 稍微熟悉一点,这可能会让您觉得很熟悉,因为您一直在处理元组 {Module, Function, Args}

【讨论】:

    【解决方案2】:

    Erlang 和 Elixir 中的函数由模块/名称/arity 唯一标识。为了导入/排除正确的功能,您需要指定所有三个部分。另一种理解这一点的方法是考虑捕获函数引用的情况,例如&Map.get/2.

    即使两个函数同名,它们对于虚拟机来说实际上是完全不同的函数。为了引用正确的,您必须正确识别您要调用的函数,因此需要使用onlyexcept 指定所有三个组件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-15
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-10-07
      • 2011-02-03
      相关资源
      最近更新 更多