简体   繁体   English

文件夹不返回无限列表

[英]foldr not returning with an infinite list

I've read https://www.haskell.org/haskellwiki/Foldl_as_foldr and a few other blog posts about the difference between foldl and foldr. 我已阅读https://www.haskell.org/haskellwiki/Foldl_as_foldr和其他一些有关foldl和foldr之间差异的博客文章。 Now I'm trying to write the fibonacci sequence as an infinite list with a foldr and I've come up with the following solution: 现在,我尝试使用文件夹将斐波那契数列编写为无限列表,并提出了以下解决方案:

fibs2 :: [Integer]
fibs2 = foldr buildFibs [] [1..]
  where
    buildFibs :: Integer -> [Integer] -> [Integer]
    buildFibs _ [] = [0]
    buildFibs _ [0] = [1,0]
    buildFibs _ l@(x:s:z) = (x + s):l

But when I do take 3 fibs2 , the function doesn't return. 但是当我take 3 fibs2 ,该函数不会返回。 I thought foldr being body recursive allows for you to use it with infinite lists in these types of situation. 我认为文件夹递归可以在这些情况下与无限列表一起使用。 Why won't this work with my solution? 为什么这不适用于我的解决方案?

Ask yourself: which fibonacci number will be the first one in the list? 问自己:哪个斐波那契数字将是列表中的第一个? My reading of your code is that the answer to this question is, "the biggest one" (notionally, each iteration of buildFibs adds a slightly larger number to the head of the resulting list). 我对您的代码的理解是,该问题的答案是“最大的问题”(概念上,每次buildFibs迭代buildFibs在结果列表的buildFibs添加一个稍大的数字)。 Since there are infinitely many fibonacci numbers, this takes a while to compute! 由于有无数斐波纳契数,因此计算需要一段时间!

This is a great exercise for equational reasoning: 这是进行方程式推理的好方法:

fibs2 = foldr buildFibs [] [1..]

foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)

foldr buildFibs [] [1..] =
    buildFibs 1 (foldr buildFibs [] [2..]) =
    buildFibs 1 (buildFibs 2 (foldr buildFibs [] [3..])) =
    buildFibs 1 (buildFibs 2 (buildFibs 3 (foldr buildFibs [] [4..]))) =
    ...

I hope by now you can see the problem: foldr is trying to traverse the entire list before returning. 我希望现在您可以看到问题所在: foldr在返回之前试图遍历整个列表。 What happens if we were to use foldl instead? 如果我们改用foldl会怎样?

foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs

buildFibs' = flip buildFibs

foldl buildFibs' [] [1..] =
    foldl buildFibs' (buildFibs 1 []) [2..] = 
    foldl buildFibs' [0] [2..] =
    foldl buildFibs' (buildFibs 2 [0]) [3..] =
    foldl buildFibs' [0,1] [3..] =
    foldl buildFibs' (buildFibs 3 [0,1]) [4..] =
    foldl buildFibs' (0+1 : [0,1]) [4..] =
    foldl buildFibs' [1,0,1] [4..] =
    foldl buildFibs' (buildFibs 4 [1,0,1]) [5..] =
    foldl buildFibs' (1+0 : [1,0,1]) [5..] =
    foldl buildFibs' [1,1,0,1] [5..] =
    foldl buildFibs' (buildFibs 5 [1,1,0,1]) [6..] =
    foldl buildFibs' [2,1,1,0,1] [6..] =
    -- For brevity I'll speed up the substitution
    foldl buildFibs' [3,2,1,1,0,1] [7..] =
    foldl buildFibs' [5,3,2,1,1,0,1] [8..] =
    foldl buildFibs' [8,5,3,2,1,1,0,1] [9..] =
    ...

So as you can see you can actually calculate the Fibonacci numbers using buildFibs and foldl , but unfortunately you're building an infinite list of them backwards, you'll never be able to calculate a specific element in the list because foldl will never terminate. 因此,如您所见,您实际上可以使用buildFibsfoldl计算斐波那契数,但是不幸的是,您向后建立了一个无限的列表,您将永远无法计算列表中的特定元素,因为foldl永远不会终止。 You can calculate a finite number of them though: 但是,您可以计算有限数量的它们:

> take 10 $ foldl buildFibs' [] [1..10]
[34,21,13,8,5,3,2,1,1,0]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM