我自己发现foldl
(or foldl'
) 是当您想要将列表汇总为一个结果 (ie sum
)foldr
时的最佳方法,并且是当您想要生成另一个 (甚至可能是无限的) 列表 (ie filter
) 时的最佳方法。
所以我正在考虑将这两者结合起来的处理。所以我做了这个功能sum_f
。sum_f
相当简单,它所做的只是将列表的元素相加,但如果它找到一个f x
为真的元素,它会将当前结果作为列表的元素作为输出,并从该点开始求和。
代码在这里:
sum_f :: (Num a) => (a -> Bool) -> [a] -> [a]
sum_f f =
let
sum_f_worker s (x:xs) =
let
rec_call z = sum_f_worker z xs
next_sum = s + x
in
next_sum `seq` if (f x) then next_sum : (rec_call 0) else rec_call next_sum
sum_f_worker _ [] = []
in
sum_f_worker 0
例如,现在让我们对所有按 2 的任意幂分组的正整数求和。这应该输出以下内容:
[1, 2, 3+4, 5+6+7+8, 9+10+11+12+13+14+15+16, ...]
IE
[1, 2, 7, 26, 100, ...]
我们可以这样做:
import Data.Bits
main =
let
power_of_two x = (x .&. (x - 1)) == 0 -- .&. is bitwise and
in
print $ take 25 $ sum_f power_of_two [(1::Integer)..]
现在,上面的函数(我相信)在恒定空间(如foldl'
)中运行,即使组呈指数增长。此外,它适用于无限列表(如foldr
)。
我想知道我是否可以在没有显式递归的情况下使用前奏函数编写上述内容(即只有前奏函数内部的递归)。还是结合这里的foldl
and的思想foldr
意味着这里的递归不能用标准的前奏函数来完成,需要显式?