我记得当我展示了一些我写给我教授的代码时,他评论说,
这很重要,但值得注意的是,
fold*
比SML / NJ中的fold*'
更有效,所以在可能的情况下,您应该优先于fold*
。
我忘了fold*
是foldr
还是foldl
。我知道这是微观优化之一,可能在实践中没有太大的区别,但是当我有选择时,我想养成使用效率更高的习惯。
哪个是哪个?我的猜测是这是特定于SML / NJ的,并且MLton将足够聪明以优化同一机器代码,但其他编译器的答案很有用。
答案 0 :(得分:3)
首选将给定输入转换为预期输出的输出。
如果两者产生相同的输出,例如总和,并且如果处理list
,则从左侧折叠将更有效,因为折叠可以从头元素开始,而从右边折叠将首先在计算第一个中间结果之前,需要遍历列表以找到最后一个元素。
对于数组和类似的随机访问数据结构,可能没有太大区别。
总是选择左右更好的编译器优化需要编译器确定左和右在所有可能的输入上是等效的。由于foldl
和foldr
将函数作为参数,因此这是一个很高的命令。
答案 1 :(得分:3)
foldl
是尾递归的,而foldr
则不是。虽然你可以通过反转列表(尾部递归)以尾递归方式执行foldr
,然后执行foldl
。
如果你折叠巨大的名单,这只会很重要。
答案 2 :(得分:1)
我会在这里保留接受的答案,但我有机会和我的教授说话,而他的回答却恰恰相反,因为我忘了我的一部分问题。有问题的代码正在建立一个列表,他说:
如果可能,请
foldr
优先于foldl
,因为如果您通过在折叠期间附加元素来构建列表,最终会为您节省reverse
。
就像在一个简单的例子中一样:
- val ls = [1, 2, 3];
val ls = [1,2,3] : int list
- val acc = (fn (x, xs) => x::xs);
val acc = fn : 'a * 'a list -> 'a list
- foldl acc [] ls;
val it = [3,2,1] : int list
- foldr acc [] ls;
val it = [1,2,3] : int list
反向的O(n)
保存可能比此问题的答案中提到的foldl
和foldr
之间的其他差异更为重要。