使用Haskell中的列表推导表示Fibonacci数

Sam*_*Sam 5 haskell list-comprehension fibonacci

我编写了以下代码来生成包含Fibonacci数字的列表.

fibonacci = [a + b | a <- 1:fibonacci, b <- 0:1:fibonacci]
Run Code Online (Sandbox Code Playgroud)

我希望列表[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,2,3,5,8,13..]0:1:[1,2,3,5,8,13..]1:fibonacci0:1:fibonacci

我已经查找了实现此序列的其他方法,但我真的想知道为什么我的代码不起作用.

Sho*_*hoe 8

问题

附:

fibonacci = [a + b | a <- 1:fibonacci, b <- 0:1:fibonacci]
Run Code Online (Sandbox Code Playgroud)

您正在生成两个列表的所有可能组合.例如:

x = [a + b | a <- [1, 2], b <- [3, 4]]
Run Code Online (Sandbox Code Playgroud)

结果将是:

[1 + 3, 1 + 4, 2 + 3, 2 + 4]
Run Code Online (Sandbox Code Playgroud)

Live demo

zipWith

你最接近的是zipWith:

fibonacci :: [Int]
fibonacci = zipWith (+) (1:fibonacci) (0:1:fibonacci)
Run Code Online (Sandbox Code Playgroud)

Live demo


J. *_*son 8

列表理解模型

  • 非确定性
  • 笛卡尔积
  • 嵌套for-loops

这些都是等价的.所以你的Fibonacci序列是错误的,因为它的计算方式太多了.在伪代码中它有点像

fibonacci = 
  for i in 1:fibonacci:
    for j in 0:1:fibonacci:
      i + j
Run Code Online (Sandbox Code Playgroud)

你真正想要的是将列表压缩在一起,按照斐波纳契的长度而不是它的平方来执行计算.要做到这一点,我们可以使用zipWith,并用一点代数,得到标准的"棘手的纤维"

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
Run Code Online (Sandbox Code Playgroud)

然后我们定义

fibonacci' = 0:1:fibonacci
fibonacci' = 0:1:zipWith (+) (0:1:fibonacci) (tail (0:1:fibonacci))
fibonacci' = 0:1:zipWith (+) fibonacci' (tail fibonacci')
Run Code Online (Sandbox Code Playgroud)

这是标准的

fibonacci = drop 2 fibonacci'
Run Code Online (Sandbox Code Playgroud)

您还可以使用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]
Run Code Online (Sandbox Code Playgroud)


Don*_*art 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]
Run Code Online (Sandbox Code Playgroud)

哪个有效,正如您所期望的那样.

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]
Run Code Online (Sandbox Code Playgroud)