Scala 对foldLeft实现的理解

Scala 对foldLeft实现的理解,scala,fold,Scala,Fold,你好! 你能解释一下这个foreach(x=> 它是如何工作的?为什么不使用地图 这是怎么回事 首先,this-foreach(f)可以被分解成this.foreach(f)(参见Arity-1部分)。其次,foreach需要一个具有“副作用”的函数和一个单元返回值。它对每个元素应用该函数一次,可能会更新一些“状态”。在这种情况下,请注意函数体(=>运算符的右侧)为var result分配一个新值:它在每次迭代时更新,其中每次迭代使用前一次更新的值(从值z开始) 为什么不使用map map生成一

你好!

你能解释一下这个foreach(x=> 它是如何工作的?为什么不使用地图

这是怎么回事

首先,
this-foreach(f)
可以被分解成
this.foreach(f)
(参见Arity-1部分)。其次,
foreach
需要一个具有“副作用”的函数和一个
单元
返回值。它对每个元素应用该函数一次,可能会更新一些“状态”。在这种情况下,请注意函数体(
=>
运算符的右侧)
var result
分配一个新值:它在每次迭代时更新,其中每次迭代使用前一次更新的值(从值
z
开始)

为什么不使用
map


map
生成一个新集合作为返回值,这里根本不需要它-我们只对这个匿名函数的“副作用”感兴趣(即更新
result
的值)如果我们在这个函数中使用
map
,如果
Unit
s,那么它将导致一个无用的集合。

map
用于迭代集合的所有成员,应用一些转换并返回另一个/相同的集合。而
foreach
用于side效果


在这里,我们对
结果
和集合的连续元素(即
x
)应用二进制运算符
op
),以获得类型
B
的结果,该类型不一定是集合。这就是为什么不使用
map

有两个答案:第一个答案是,如果您在这里直接使用
map
而不是
foreach
,那么代码仍然有效。您只需要使用可以说“太强大了”。实际上,您并不关心
foreach
中的表达式返回什么,您只关心它在每次迭代中产生的副作用(对
var
的更新)

foreach
这里的功能与命令式
for
循环的功能相同

def foldLeft[B](z: B)(op: (B, A) => B): B = 
           var result = z
           this foreach (x => result = op(result, x))
           result
//荒谬的C
int x=for(int i=0;i<10;i++){
x++;
}
而只是写

// Nonsensical C
int x = for (int i = 0; i < 10; i++) {
    x++;
}
//我们不分配循环
int x=0;
对于(int i=0;i<10;i++){
x++;
}
回答您问题的第二种方法来自Scala社区的一个传统,即在执行
映射时(或在包含折叠的集合上进行任何类型的遍历时)不会产生副作用。此规则的例外是任何返回
单位的内容(例如
foreach
),因为否则这些表达式将完全无用

因此,牢记这一传统,为什么还要有这种副作用,而不仅仅是使用基于
映射的实现

如果我们不想让map产生副作用,我们就不能在map中实现
foldLeft
,除非Scala中有一个非常奇怪的
map
map
版本独立地作用于集合的每个元素(有充分的理由),而
foldLeft
必须保持某种上下文(蓄能器)当它遍历一个集合时,它可能会使用该集合来影响集合中每个元素发生的事情。
map
对集合中除当前元素以外的任何元素的独立性和
foldLeft
允许对过去值的潜在依赖性基本上是不一致的;后者严格来说更强大(您可以根据
foldLeft
实现
map
,请参见注释)

这意味着为了实现折叠,我们必须使用更强大的技术来遍历数据结构。这归结为两种选择:

  • 递归
  • 循环
实现者在这里选择后者而不是递归


注意:根据你对
map
的定义,这里有一点细微的差别。如果你想
map
遵守函子定律,你可以用折叠创建一个非一致的
map
,但是只要
map
的一致版本存在,那么你就可以用折叠创建它。

我的意思是
这个foreach
==请注意,映射并不总是导致大小相同的事物。集合和映射是两个示例。同意您的意见。更正它。
// We don't assign the loop
int x = 0;
for (int i = 0; i < 10; i++) {
    x++;
}