可以折叠用于创建无限列表吗?

Dra*_*gno 6 haskell

我编写了以下代码,它创建了一个无限的Fibonacci数列表:

fibs = 1:1:fib 1 1
  where fib a b = a+b:fib b (a+b)
Run Code Online (Sandbox Code Playgroud)

上面的代码可以使用foldlfoldr避免递归吗?

pig*_*ker 14

这些foldlfoldr功能是列表消费者.正如svenningsson的回答正确指出的那样,unfoldr是一个适合捕获共同结构的列表生成器.fibs

然而,考虑到foldlfoldr在他们的返回类型,即他们通过消耗列表产生什么多态,这是合理的问他们是否可能被用来消耗一个列表,并产生另一种.这些产生的列表中的任何一个都可能无限吗?

看看的定义 foldl

foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f a []        = a
foldl f a (b : bs)  = foldl f (f a b) bs
Run Code Online (Sandbox Code Playgroud)

我们看到,为了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)
Run Code Online (Sandbox Code Playgroud)

它承认f可能为b输入中消耗的每个产生一些输出的懒惰可能性.操作如

map g = foldr (\ b gbs -> g b : gbs) []   -- golfers prefer ((:) . g)
stutter = foldr (\ x xxs -> x : x : xxs) []
Run Code Online (Sandbox Code Playgroud)

为每个输入产生一点输出,从无限输入提供无限输出.

因此,一个厚颜无耻的人可以表达任何无限递归作为foldr无限列表上的非递归.例如,

foldr (\ _ fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) undefined [1..]
Run Code Online (Sandbox Code Playgroud)

(编辑:或者,就此而言

foldr (\_ fib a b -> a : fib b (a + b)) undefined [1..] 1 1
Run Code Online (Sandbox Code Playgroud)

这更接近问题中的定义.)

虽然这种观察虽然是真实的,但并不能说明健康的编程风格.

  • 我的术语中的`fib`与lambda绑定,不是由递归定义的.另一方面,我正在使用`foldr`来构建通用的fixpoint运算符. (2认同)

sve*_*son 11

我不知道是否可以创建无限列表foldl.你可以通过使用来解决这个问题foldr,但是你必须创建另一个折叠列表.那份清单是什么?斐波那契数字没有任何暗示它们是从其他列表中生成的.

你想要的是使用unfoldr.它可以用来创建列表,而不是消耗他们,因为是这样的foldlfoldr.以下是如何使用unfoldr生成无限的斐波纳契数列表.

fib = unfoldr (\(a,b) -> Just (a,(b,a+b))) (1,1)
Run Code Online (Sandbox Code Playgroud)

您可以unfoldrData.List基础包中的模块中找到.