【问题标题】:Understand Function capturing through map and reduce通过map和reduce理解函数捕获
【发布时间】:2017-08-19 09:43:24
【问题描述】:

我是 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

【问题讨论】:

  • 你说“捕获第二个参数”是什么意思?快速浏览您链接的文档,在我看来,在 elixir 的上下文中捕获是指通过 & 运算符将函数用作值。所以我不确定捕获参数意味着什么。
  • 好吧,你是对的,如果我们考虑到(通过 & 运算符使用函数作为值)我们如何在地图中应用它并减少。

标签: dictionary functional-programming elixir reduce


【解决方案1】:

map/2reduce/2 是两个不同的函数。

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

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

【讨论】:

    【解决方案2】:

    基本上:

    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 
    

    【讨论】:

      【解决方案3】:

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

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

      或者,使用简写和枚举参数:

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

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

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

      后者虽然看起来很麻烦,但只是用它的 arity 编写函数名称的常用方法。 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))
      
      —
      

      这里没有第三种表示法,因为没有这样的函数,它接受一个数字并返回它的双倍值。但有人可能会宣布她自己的:

      defmodule Arith, do: def dbl(p1), do: p1 * 2
      
      Enum.map([1, 2, 3], &Arith.dbl/1) # map expects arity 1
      #⇒ [2, 4, 6]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-27
        • 1970-01-01
        • 1970-01-01
        • 2021-07-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多