通过map和reduce来理解函数捕获

时间:2017-03-26 19:40:02

标签: dictionary functional-programming elixir reduce

我是Elixir语言的初学者,所以在打击示例中

iex> Enum.reduce([1, 2, 3], 0, &+/2)
      6

iex> Enum.map([1, 2, 3], &(&1 * 2))
     [2, 4, 6]

在reduce方法中,我理解我们捕获第二个arg,然后我们将列表值添加到它,直到我们到达List的末尾。

但是在map方法中我无法理解捕获的工作原理?

参考

http://elixir-lang.org/getting-started/recursion.html

3 个答案:

答案 0 :(得分:6)

map/2reduce/2是两个不同的功能。

map/2获取一些值和一个带有单个值的函数,并将该函数应用于集合中的每个元素,从而有效地将其转换为列表。

reduce/2接受一些值和一个带2个参数的函数。该函数的第一个参数是集合中的元素,而第二个参数是累加器。因此,该功能可将您的收藏减少到单个值。

使用语法&+/2,这不会捕获第二个参数。它在两个参数上调用+函数。 /2表示它具有2的arity(它需要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

它们是类似的概念,但略有不同。

答案 1 :(得分:0)

基本上:

map会因为在列表的每个元素上应用函数而返回新列表

reduce返回列表中应用函数计算的结果 - 您将整个集合缩减为(很可能)一个结果,例如。整数

在你的例子中:

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 

答案 2 :(得分:0)

表达匿名函数有三种不同的方法,当它作为参数传递时:

Enum.reduce([1, 2, 3], 0, fn p1, p2 -> p1 + p2 end)

或者,使用速记和列举的参数:

Enum.reduce([1, 2, 3], 0, &(&1 + &2))

或明确命名相应arity的函数(2reduce,因为reduce需要arity 2的函数):

Enum.reduce([1, 2, 3], 0, &+/2)

后者虽然看起来很麻烦,但只是用它的arity写一个函数名的常用方法。 Kernel.+/2是此处的函数名称。如果您使用自己的函数作为reducer:

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))

—

第三种符号在这里不可用,因为没有这样的函数,它接受一个数字并返回它的加倍值。但有人可能会声明自己:

defmodule Arith, do: def dbl(p1), do: p1 * 2

Enum.map([1, 2, 3], &Arith.dbl/1) # map expects arity 1
#⇒ [2, 4, 6]