Scala:reduceLeft 和 reduceRight 是否在不同位置有累加器?

Scala: Does reduceLeft and reduceRight have accumulator at different positions?

我对 Scala 中的 reduceleft 和 reduceRight 方法有点困惑。这是我正在测试的片段:

val intList = List(5, 4, 3, 2, 1);
    println(intList.reduceRight((curr, acc) => { //Reduce right me y is accumulator
        println(s"First  Curr = $curr, Acc = $acc")
        curr - acc
    }));
    println(intList.reduceLeft((curr, acc) => { // List(1,2,3,4,5) // Accumulator is the first Element
    println(s"Second Curr = $curr, Acc = $acc")
    acc - curr}))

输出如下所示:

First  Curr = 2, Acc = 1
First  Curr = 3, Acc = 1
First  Curr = 4, Acc = 2
First  Curr = 5, Acc = 2
3
Second Curr = 5, Acc = 4
Second Curr = -1, Acc = 3
Second Curr = 4, Acc = 2
Second Curr = -2, Acc = 1

在两次迭代中,我观察到的是,在 reduceRight 的情况下,我们有 (curr,acc) [意思是 curr 作为第一个参数传递,累加器作为第二个传递],而如果在 reduceLeft 中我们有 (acc,curr).

这种论点不一致背后有什么具体原因吗?

让我们使用一点可视化:

reduceLeft:

                 a  b c d e
  acc1 = f(a, b)  \/ / / /
acc2 = f(acc1, c)  \/ / /
 acc3 = f(acc2, d)  \/ /
  acc4 = f(acc3, e)  \/

reduceRight:

a b c d  e
 \ \ \ \/  acc1 = f(d, e)
  \ \ \/  acc2 = f(c, acc1)
   \ \/  acc3 = f(b, acc2)
    \/  acc4 = f(a, acc3)

参数的顺序帮助我们记住参数的来源和计算顺序。因为这对于不要混淆左关联和右关联操作非常重要:

  • 任何视觉帮助都很重要,在函数的正确一侧写 acc 会使推理更容易
  • 如果 coll.reduceLeft(_ operation _)coll.reduceRight(_ operation _) 中的
  • lambda 表达式 非常 令人困惑的行为 acc 在这两种情况下

想象一下,如果您定义了一个右结合运算符,例如a ** b(a 的 b 次方)。数学中的求幂是右结合的,所以 a ** b ** c 应该表现得像 a ** (b ** c)。有人决定使用 rightReduce 来计算这种用例,因为它恰好实现了这种行为。他们

List(a, b, c).reduceRight(_ ** _)

然后他们得知有人决定 acc 应该在左侧,因为他们希望它与 reduceLeft“一致”。 将与您从数学中获得的每一个直觉更加不一致。