怎么用FoldRight
实现FoldLeft
呢?两个函数的签名如下
def foldLeft[A,B]: (List[A], B) => ((B, A) => B) => B
def foldRight[A,B]: (List[A], B) => ((A, B) => B) => B
最简单的方式就是先把列表翻转,头变尾,然后对翻转后的列表直接使用foldRight
就可以了。
def foldLeftViaFoldRight[A,B](l: List[A], z: B)(f: (B, A) => B): B =
foldRight(reverse(l), z)((x, acc) => f(acc, x))
能不能直接对原列表使用foldRight
呢?先来看一个例子:对于List(X1, X2, X3, X4)
,分别使用二者的等效表达式为
foldLeft = f(f(f(f(z, X1), X2), X3), X4) // from left to right
foldRight = f(X1, f(X2, f(X3, f(X4, z)))) // from right to left
foldLeft
从左向右计算,foldRight
从右向左计算。要用foldRight
实现与foldLeft
一样的效果,那么就要把计算推迟,不能让计算从右边发生。
我们可以使用函数来使真正的计算从左往右进行。即给foldRight
传入的z
是一个函数,foldRight
的计算结果也是一个函数,得到的这个函数接收真正的z
,进而完成计算。
def foldLeftViaFoldRight2[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
val g: (A, (B => B)) => B => B =
(a: A, acc: (B => B)) =>
(b: B) => acc(f(b, a))
val id: (B => B) = (b: B) => b
val delay: (B => B) = foldRight(l, id)(g)
delay(z)
}
id
函数返回传入的参数,仅仅是为了推迟计算。解释如下
l : [X1, X2, X3......Xn]
acc = id // init
acc = (b: B) => id(f(b, Xn+1)) // n + 1
acc = (b: B) =>
((b2 :B) => id(f(b2, Xn+1))) (f(b, Xn)) // pass f(b, Xn) to b2
= (b: B) =>
id(f(f(b, Xn), Xn+1)) // n
...............................
acc = (b: B) =>
id(f(...f(f(f(f(b, X1), X2), X3), X4)..., Xn))
acc(z) = foldLeft(l, z)(f)