我编写了以下代码来生成包含Fibonacci数字的列表。
fibonacci = [a + b | a <- 1:fibonacci, b <- 0:1:fibonacci]
我希望列表的输出为[1,2,3,5,8,13..]
,但输出不是Fibonacci序列。
我不太明白为什么它不起作用。
我的理由是,如果斐波纳契数是[1,2,3,5,8,13..]
,那么这将等于2个列表[1,1,2,3,5,8,13..]
和[0,1,1,2,3,5,8,13..]
的总和,它们相当于{{1} }和1:[1,2,3,5,8,13..]
或0:1:[1,2,3,5,8,13..]
和1:fibonacci
我已经查找了实现此序列的其他方法,但我真的很想知道为什么我的代码无法正常工作。
答案 0 :(得分:8)
使用:
fibonacci = [a + b | a <- 1:fibonacci, b <- 0:1:fibonacci]
您正在生成两个列表的所有可能组合。例如:
x = [a + b | a <- [1, 2], b <- [3, 4]]
结果将是:
[1 + 3, 1 + 4, 2 + 3, 2 + 4]
zipWith
最接近的是zipWith
:
fibonacci :: [Int]
fibonacci = zipWith (+) (1:fibonacci) (0:1:fibonacci)
答案 1 :(得分:8)
列表理解模型
for
- 循环都是等价的。所以你的Fibonacci序列是错误的,因为它的计算方式太多了。在伪代码中,它有点像
fibonacci =
for i in 1:fibonacci:
for j in 0:1:fibonacci:
i + j
你真正想要的是将列表压缩在一起,按照斐波那契的长度而不是方形的顺序进行计算。要做到这一点,我们可以使用zipWith
,并使用一点代数,获得标准的&#34;棘手的fibo&#34;
fibonacci = zipWith (+) (1:fibonacci) (0:1:fibonacci)
fibonacci = zipWith (+) (0:1:fibonacci) (1:fibonacci) -- (+) is commutative
fibonacci = zipWith (+) (0:1:fibonacci) (tail (0:1:fibonacci)) -- def of tail
然后我们定义
fibonacci' = 0:1:fibonacci
fibonacci' = 0:1:zipWith (+) (0:1:fibonacci) (tail (0:1:fibonacci))
fibonacci' = 0:1:zipWith (+) fibonacci' (tail fibonacci')
这是
的标准fibonacci = drop 2 fibonacci'
您还可以使用ParallelListComprehension
扩展程序,它允许您使用略有不同的语法对列表推导进行压缩
{-# ParallelListComp #-}
fibonacci = [a + b | a <- 1:fibonacci | b <- 0:1:fibonacci]
> take 10 fibonacci
[1,2,3,5,8,13,21,34,55,89]
答案 2 :(得分:6)
列表理解不是那样的。您已编写嵌套遍历,而您尝试执行的操作是zip
。
要了解其中的差异,请考虑:
Prelude> let fibs = [ a + b | (a,b) <- zip (1 : fibs) (0 : 1 : fibs) ]
Prelude> take 10 fibs
[1,2,3,5,8,13,21,34,55,89]
哪种方式可以预期。
Haskell有一个语法扩展,允许并行理解,所以语法为你做了一个zip。您可以使用-XParallelListComp
启用它,然后写:
Prelude> let fibs = [ a + b | a <- 1 : fibs | b <- 0 : 1 : fibs ]
Prelude> take 10 fibs
[1,2,3,5,8,13,21,34,55,89]
答案 3 :(得分:0)
没有zip
或ParallelListComprehension
的另一种解决方案是:
> fib = 0:1:[ last x + head y | x:y:[] <- [ [take i fib, drop i fib] | i <- [1,2..] ] ]
> take 10 fib
[0,1,1,2,3,5,8,13,21,34]