Gui*_*los 10 functional-programming elixir
我正在研究Elixir,当我从模块导入函数时使用only或except运算符时,我需要指定一个arity数.为什么?
例如
import :math, only: [sqrt: 1]
Run Code Online (Sandbox Code Playgroud)
要么
import :math, except: [sin: 1, cos: 1]
Run Code Online (Sandbox Code Playgroud)
zxq*_*xq9 14
在Erlang生态系统中,函数由name + arity标识.在大多数其他语言中,您可以按名称重载函数.换句话说,在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).
Run Code Online (Sandbox Code Playgroud)
请注意,有两个句点,这意味着这里有两个完全独立的定义.我们也可以写:
fac(N) -> sum(1, N).
sum(A, 0) -> A;
sum(A, N) -> sum(A * N, N - 1).
Run Code Online (Sandbox Code Playgroud)
但是你会注意到第二个版本在字符笔划方面的节省大大超过了它的语义卷积 - 第二个版本的内部函数名称是一个彻头彻尾的谎言!
惯例是将相关函数命名为相同的东西,但实际上,在Erlang生态系统中不允许使用arity重载函数.为了使这样的重载可接受,需要对编译器编译Erlang的字节码的编译器进行大量的功能添加,这将是痛苦工作的毫无意义的浪费.目前的情况与动态类型的函数式语言一样好(没有它成为静态类型的函数式语言......而这完全是另一个讨论).
最终结果是您必须准确指定要导入的函数,无论是在Erlang还是Elixir中,这意味着通过名称+ arity来标识它.认识到常见的约定是对执行相同但具有不同参数计数的函数使用相同的名称(通常只是编写一系列curried定义来包含常见的默认值),Elixir提供了一种快捷方式,可以按组包含函数而不是枚举他们.
因此,当你import :math, only: [sqrt: 1]只拿走math:sqrt/1并离开模块的其余部分时(如果有的math:sqrt/2话,你会忽略它).当import :math, except: [sin: 1, cos: 1]你把一切却 math:sin/1并math:cos/1(在那里一个math:sin/2你会采取它).名称+ arity是一个独特的身份.想象一下可用功能的大型KV商店.键是{module, func, arity},意味着它们是系统的原子值.如果你对Erlang很熟悉,这可能会让你感到熟悉,因为你总是处理元组{Module, Function, Args}.
Erlang和Elixir中的函数由module/name/arity唯一标识.要导入/排除正确的功能,您需要指定所有三个部分.理解这一点的另一种方法是考虑捕获函数引用的情况,例如&Map.get/2.
即使两个函数共享相同的名称,它们实际上与VM完全不同.为了引用正确的一个,你必须正确地识别你要调用的函数,因此需要与指定所有三个组成部分only,except.