通过 map 和 reduce 理解函数捕获
Understand Function capturing through map and reduce
我是 Elixir 语言的初学者,所以在下面的例子中
iex> Enum.reduce([1, 2, 3], 0, &+/2)
6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
在 reduce 方法中,我了解到我们 捕获 第二个 arg 并向其添加列表值,直到我们到达列表的末尾。
但是在 map 方法中我无法理解捕获是如何工作的?
参考
map/2
采用一些值和一个采用单个值的函数,并将该函数应用于集合中的每个元素,有效地将其转换为列表。
reduce/2
接受一些值和一个接受 2 个参数的函数。该函数的第一个参数是集合中的元素,而第二个参数是累加器。因此该函数将您的集合缩减为单个值。
使用语法 &+/2
,这不会捕获第二个参数。它在两个参数上调用 +
函数。 /2
表示它的元数为 2(它需要 2 个参数)。以下面的代码为例。
iex(1)> fun = &+/2
&:erlang.+/2
iex(2)> fun.(1,2)
3
这里,我们将+
函数设置为变量fun
。然后我们可以将该函数应用于我们的参数以获得一个值。
另一种语法 &(&1 * 2)
创建一个匿名函数,它接受我们的唯一参数(由 &1
表示)并将其乘以 2。初始 &
只是意味着它是一个匿名函数。
iex(3)> fun2 = &(&1 * 2)
#Function<6.118419387/1 in :erl_eval.expr/5>
iex(4)> fun2.(5)
10
它们是相似的概念,但略有不同。
基本上:
map
returns 对列表的每个元素应用函数后得到的新列表
reduce
returns 您是在列表上应用函数的计算结果 - 您将整个集合减少为(很可能)一个结果,例如。整数
在你的例子中:
iex> Enum.reduce([1, 2, 3], 0, &+/2)
# it equals:
0 + 1 # first step, 1 is out of the list now
1 + 2 # second step, 2 is out of the list now
3 + 3 # last step, 3 is out of the list now, return 6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
# apply for each element function fn(x) -> 2 * x end, but with syntactic sugar
在将匿名函数作为参数传递时,可以通过三种不同的方式表达:
Enum.reduce([1, 2, 3], 0, fn p1, p2 -> p1 + p2 end)
或者,使用 shorthand 和枚举参数:
Enum.reduce([1, 2, 3], 0, &(&1 + &2))
或者,显式命名相应元数的函数(2
对应 reduce
,因为 reduce
需要一个元数 2
的函数:
Enum.reduce([1, 2, 3], 0, &+/2)
后者虽然看起来很麻烦,但只是一种常见的写函数名的方式。 Kernel.+/2
这里是一个函数名。如果您使用自己的函数作为减速器:
defmodule My, do: def plus(p1, p2), do: p1 + p2
Enum.reduce([1, 2, 3], 0, &My.plus/2)
以上三种方式都是100%等价的。
JIC:对于映射器,这三种方式是:
Enum.map([1, 2, 3], fn p -> p * 2 end)
Enum.map([1, 2, 3], &(&1 * 2))
—
第三种表示法在这里不可用,因为没有这样的函数,它接受一个数字 returns 它是双倍的值。但有人可能会宣布她自己的:
defmodule Arith, do: def dbl(p1), do: p1 * 2
Enum.map([1, 2, 3], &Arith.dbl/1) # map expects arity 1
#⇒ [2, 4, 6]
我是 Elixir 语言的初学者,所以在下面的例子中
iex> Enum.reduce([1, 2, 3], 0, &+/2)
6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
在 reduce 方法中,我了解到我们 捕获 第二个 arg 并向其添加列表值,直到我们到达列表的末尾。
但是在 map 方法中我无法理解捕获是如何工作的?
参考
map/2
采用一些值和一个采用单个值的函数,并将该函数应用于集合中的每个元素,有效地将其转换为列表。
reduce/2
接受一些值和一个接受 2 个参数的函数。该函数的第一个参数是集合中的元素,而第二个参数是累加器。因此该函数将您的集合缩减为单个值。
使用语法 &+/2
,这不会捕获第二个参数。它在两个参数上调用 +
函数。 /2
表示它的元数为 2(它需要 2 个参数)。以下面的代码为例。
iex(1)> fun = &+/2
&:erlang.+/2
iex(2)> fun.(1,2)
3
这里,我们将+
函数设置为变量fun
。然后我们可以将该函数应用于我们的参数以获得一个值。
另一种语法 &(&1 * 2)
创建一个匿名函数,它接受我们的唯一参数(由 &1
表示)并将其乘以 2。初始 &
只是意味着它是一个匿名函数。
iex(3)> fun2 = &(&1 * 2)
#Function<6.118419387/1 in :erl_eval.expr/5>
iex(4)> fun2.(5)
10
它们是相似的概念,但略有不同。
基本上:
map
returns 对列表的每个元素应用函数后得到的新列表
reduce
returns 您是在列表上应用函数的计算结果 - 您将整个集合减少为(很可能)一个结果,例如。整数
在你的例子中:
iex> Enum.reduce([1, 2, 3], 0, &+/2)
# it equals:
0 + 1 # first step, 1 is out of the list now
1 + 2 # second step, 2 is out of the list now
3 + 3 # last step, 3 is out of the list now, return 6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
# apply for each element function fn(x) -> 2 * x end, but with syntactic sugar
在将匿名函数作为参数传递时,可以通过三种不同的方式表达:
Enum.reduce([1, 2, 3], 0, fn p1, p2 -> p1 + p2 end)
或者,使用 shorthand 和枚举参数:
Enum.reduce([1, 2, 3], 0, &(&1 + &2))
或者,显式命名相应元数的函数(2
对应 reduce
,因为 reduce
需要一个元数 2
的函数:
Enum.reduce([1, 2, 3], 0, &+/2)
后者虽然看起来很麻烦,但只是一种常见的写函数名的方式。 Kernel.+/2
这里是一个函数名。如果您使用自己的函数作为减速器:
defmodule My, do: def plus(p1, p2), do: p1 + p2
Enum.reduce([1, 2, 3], 0, &My.plus/2)
以上三种方式都是100%等价的。
JIC:对于映射器,这三种方式是:
Enum.map([1, 2, 3], fn p -> p * 2 end)
Enum.map([1, 2, 3], &(&1 * 2))
—
第三种表示法在这里不可用,因为没有这样的函数,它接受一个数字 returns 它是双倍的值。但有人可能会宣布她自己的:
defmodule Arith, do: def dbl(p1), do: p1 * 2
Enum.map([1, 2, 3], &Arith.dbl/1) # map expects arity 1
#⇒ [2, 4, 6]