foldl 和 foldr 函数是列表-消费者。正如svenningsson's answer 正确指出的那样,unfoldr 是一个列表-生产者,适合捕获fibs 的co-递归结构。
但是,鉴于foldl 和foldr 在它们的返回类型上是多态的,即它们通过使用一个列表来产生什么,因此询问它们是否可以用于使用一个列表并产生另一个列表是合理的。这些生成的列表中的任何一个可能是无限的吗?
看foldl的定义
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f a [] = a
foldl f a (b : bs) = foldl f (f a b) bs
我们看到foldl 要产生任何东西,它所使用的列表必须是有限的。因此,如果foldl f a 产生无限输出,那是因为a 是无限的,或者是因为f 有时会执行无限列表生成。
foldr 是另一回事
foldr :: (b -> a -> a) -> a -> [b] -> a
foldr f a [] = a
foldr f a (b : bs) = f b (foldr f a bs)
它承认f 可能会为输入中消耗的每个b 生成一些输出的惰性可能性。像
这样的操作
map g = foldr (\ b gbs -> g b : gbs) [] -- golfers prefer ((:) . g)
stutter = foldr (\ x xxs -> x : x : xxs) []
为每个输入产生一点点输出,从无限输入提供无限输出。
因此,厚脸皮的人可以将任何无限递归表示为无限列表上的非递归foldr。例如,
foldr (\ _ fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) undefined [1..]
(编辑:或者,就此而言
foldr (\_ fib a b -> a : fib b (a + b)) undefined [1..] 1 1
这更接近问题中的定义。)
虽然这个观察结果是正确的,但很难表明一种健康的编程风格。