作者在Functional Programming in Scala中要求通过FoldLeft表达FoldRight。然后作者提供以下implementation:
def foldRightViaFoldLeftAuthor[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
foldLeft(l, (b: B) => b)((g, a) => b => g(f(a, b)))(z)
}
有this之类的几个问题要求解释作者的解决方案。也许很多人仍在努力理解它。
当我在考虑任务时,我想出了一个不同的实现,至少对我来说似乎更具可读性和易掌握性
def foldRightViaFoldLeftMy[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
foldLeft(l, z)(((g: (A, B) => B) => (b: B, a: A) => g(a, b)) (f))
}
所以我基本上准备了一个将f(a,b)
转换为f(b,a)
的函数,现在我可以调用foldLeft
了,它是尾递归的。
所以我的问题是:
答案 0 :(得分:3)
您编写的实现具有与foldRight
相同的签名,但是当组合操作不可交换时,它的语义不正确。举个例子,空列表为零且组合操作为弊的右折应为identity:
scala> val input = List(1, 2, 3)
input: List[Int] = List(1, 2, 3)
scala> val f: (Int, List[Int]) => List[Int] = _ :: _
f: (Int, List[Int]) => List[Int] = $$Lambda$1912/991363637@5e9bf744
scala> foldRightViaFoldLeftAuthor(input, List.empty[Int])(f)
res0: List[Int] = List(1, 2, 3)
但是您的实现会颠倒列表:
scala> foldRightViaFoldLeftMy(input, List.empty[Int])(f)
res1: List[Int] = List(3, 2, 1)
这是因为即使切换了组合函数的参数顺序,您仍在从左向右折叠。我发现the Wikipedia page about fold
上的图表对于可视化差异很有用。在您的实现中,应用程序是这样发生的:
scala> f(3, f(2, f(1, Nil)))
res2: List[Int] = List(3, 2, 1)
在本书的实现中,您会有类似以下内容:
((b3: List[Int]) =>
((b2: List[Int]) =>
((b1: List[Int]) => identity(f(1, b1)))(f(2, b2)))(f(3, b3)
)
)(Nil)
归结为:
scala> f(1, f(2, f(3, Nil)))
res3: List[Int] = List(1, 2, 3)
因此,您对这两个问题的回答都是“是”,您的实现与本书的实现之间存在重要区别。