为啥需要 Elixir 捕获运算符来将函数绑定到值
Posted
技术标签:
【中文标题】为啥需要 Elixir 捕获运算符来将函数绑定到值【英文标题】:Why Is The Elixir Capture Operator Needed To Bind A Function To A Value为什么需要 Elixir 捕获运算符来将函数绑定到值 【发布时间】:2016-05-28 06:42:16 【问题描述】:我有以下灵药代码sn-p:
defmodule Rectangle do
def area(a, b) do
a * b
end
def area(a) do
a * a
end
end
然后我将文件加载到 iex 会话中,如下所示:
iex(1)> import_file "rectangle.exs"
:module, Rectangle,
<<70, 79, 82, 49, 0, 0, 5, 84, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 204, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>,
:area, 1
效果如我所愿
iex(2)> Rectangle.area(9)
81
现在我想将具有 arity 1 的区域函数分配给匿名函数,例如:
iex(3)> fun = Rectangle.area/1
** (UndefinedFunctionError) undefined function Rectangle.area/0
Rectangle.area()
但是当我输入类似:
iex(3)> fun = &Rectangle.area/1
&Rectangle.area/1
然后就可以了。虽然 Rectangle.area 已经是函数了,但是为什么elixir 函数名前面要加 &?
【问题讨论】:
这是一个公正的语法问题 - 它有点像解释器说“指向函数的指针”不是代数表达式(例如格式错误的除以 1)。请记住,Elixir 正在做“杂技”以保持与 Erlang 的兼容性 - 所以必须做出一些妥协 - 我认为。 @GavinBrelstaff 这实际上有两个原因。第一个是因为在 Elixir 语法中,parens 是可选的,引用一个函数只会调用它,除非你使用&
来表示命名函数和 arity(它需要的参数数量)。第二个原因是 Elixir 没有做任何杂技来保持与 Erlang 的兼容性,它只是假设了 Erlang 的所有语义。在 Beam VM 中,函数由名称和数量来标识。同名有 2 个 arities 实际上是 2 个不同的函数。
感谢 asonge - 我也是来学习的!仍然 IMO 允许括号在任何地方都是可选的,这对我们的用户来说非常棒,但对于维护语言的人来说,无论是否“杂技”都具有挑战性。
关于不同种类的功能很好的解释可以看这个answer
【参考方案1】:
这是因为这就是编译器解析anonymous function 的方式。
Rectangle.area/1
将被解析为 Rectangle.area
到 1
的划分(因此出现 undefined function Rectangle.area/0
错误)。
您可以使用quote
查看表达式是如何解析的:
iex> quote do &Rectangle.area/1 end
iex> quote do Rectangle.area/1 end
【讨论】:
除法与功能的关系是什么意思? @zero_coding,这就是arity - erlangcentral.org/wiki/index.php?title=Arity @zero_coding,除法不适用于函数,而是函数返回的值。在 Elixir 中(就像在 Ruby 中一样),括号对于无参数函数是可选的:Rectangle.area
与 Rectangle.area()
相同。所以编译器试图在Rectangle
中找到一个没有参数的函数area
并应用它。另一种形式 &Rectangle.area/1
告诉编译器搜索带有一个参数或 arity 1 的函数 Rectangle.area
,正如 @arathunku 指出的那样。以上是关于为啥需要 Elixir 捕获运算符来将函数绑定到值的主要内容,如果未能解决你的问题,请参考以下文章