Functional programming 在Elixir上导入函数时,仅使用或除外指定arity
我正在学习长生不老药,当我从模块导入函数时仅使用Functional programming 在Elixir上导入函数时,仅使用或除外指定arity,functional-programming,elixir,Functional Programming,Elixir,我正在学习长生不老药,当我从模块导入函数时仅使用或运算符时,我需要指定一个算术数。为什么? e、 g 或 Erlang和Elixir中的函数由module/name/arity唯一标识。为了导入/排除正确的函数,需要指定所有三个部分。理解这一点的另一种方法是考虑捕获函数引用的情况,例如“代码>和MAP.GET/2 < < /P>”。 即使两个函数共享相同的名称,它们实际上与VM完全不同。为了引用正确的函数,您必须正确标识希望调用的函数,因此需要使用仅指定所有三个组件,除了整个Erlang生态系
或运算符时,我需要指定一个算术数。为什么?
e、 g
或
Erlang和Elixir中的函数由module/name/arity唯一标识。为了导入/排除正确的函数,需要指定所有三个部分。理解这一点的另一种方法是考虑捕获函数引用的情况,例如“代码>和MAP.GET/2 < < /P>”。
即使两个函数共享相同的名称,它们实际上与VM完全不同。为了引用正确的函数,您必须正确标识希望调用的函数,因此需要使用仅指定所有三个组件,除了整个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中,这意味着通过名称+算术来识别它。Elixir认识到常见的约定是对执行相同操作但参数计数不同的函数使用相同的名称(通常只是编写一系列通用的定义来封装常见的默认值),因此Elixir提供了按组包含函数的快捷方式,而不是枚举它们
因此,当您import:math,only:[sqrt:1]
时,您只取math:sqrt/1
,而忽略了模块的其余部分(如果存在math:sqrt/2
您会忽略它)。当你导入数学时,除了:[sin:1,cos:1]
你拿走了一切,除了math:sin/1
和math:cos/1
(如果有math:sin/2
你就会拿走它)。name+arity是一个独特的标识。想象一个可用功能的大存储。键是{module,func,arity}
,这意味着它们是系统的原子值。如果您对Erlang稍有了解,您可能会觉得这很熟悉,因为您一直在处理元组{Module,Function,Args}
。因为这是Elixir独有的功能(据我所知),您可能应该从问题中删除Erlang标记。
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).