在Haskell中生成Fibonacci数?

Luc*_*cky 49 haskell fibonacci

在Haskell中,如何基于第n个Fibonacci数等于第(n-2)个Fibonacci数加上第(n-1)个Fibonacci数的属性生成Fibonacci数?

我见过这个:

fibs :: [Integer]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)

我真的不明白,或者它是如何产生无限列表而不是包含3个元素的列表.

我如何通过计算实际定义来编写haskell代码,而不是通过使用list函数做一些非常奇怪的事情?

dtb*_*dtb 84

这是一个计算第n个Fibonacci数的不同且更简单的函数:

fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
Run Code Online (Sandbox Code Playgroud)

您所指的实现是关于Fibonacci中的值如何相互关联的一些观察的中继(以及Haskell如何根据自身定义数据结构实际上创建无限数据结构)

你问题中的函数是这样的:

假设您已经拥有Fibonacci数字的无限列表:

   [ 1, 1, 2, 3, 5,  8, 13, .... ]
Run Code Online (Sandbox Code Playgroud)

tail这个名单的是

   [ 1, 2, 3, 5, 8, 13, 21, .... ]
Run Code Online (Sandbox Code Playgroud)

zipWith 使用给定运算符逐元素地组合两个列表:

   [ 1, 1, 2, 3,  5,  8, 13, .... ]
+  [ 1, 2, 3, 5,  8, 13, 21, .... ]
=  [ 2, 3, 5, 8, 13, 21, 34, .... ]
Run Code Online (Sandbox Code Playgroud)

因此,斐波那契数的无限列表可以通过在元素之前预先计算,11使用+运算符将无限的Fibonacci数列表与无限的Fibonacci数列表的尾部压缩.

现在,要获得第n个Fibonacci数,只需获得Fibonacci数无限列表的第n个元素:

fib n = fibs !! n
Run Code Online (Sandbox Code Playgroud)

Haskell的优点在于它不需要计算Fibonacci数列表中的任何元素.

我让你的头爆炸了吗?:)

  • 我喜欢这个 - 通过总结你想要弄清楚的列表的相应值来计算列表.我的大脑通常不会像那样工作 - 就像试着看着你自己的耳朵一样. (24认同)
  • @Christopher有时会省略序列的前0位. (3认同)
  • @Abarax不,实际上尾递归会让这个伎俩变得不可能.这是懒惰和保护递归,递归调用是在构造函数字段的每一步,`fibo:recursive_call`,所以为了达到它,我们必须解构前一个调用的结果.因此递归深度永远不会大于1. (3认同)
  • `fib 0 = 1`应该是`fib 0 = 0`.我只是注意到这一点,因为我只是这一次犯了同样的错误.哈哈. (2认同)
  • @Christoper 不,不是。序列只是向左移动了 1。没什么大不了的。 (2认同)
  • @Zelphir你用`0:1:zipWith(+)fibs(tail fibs)`生成无限列表.你从`[0,1 ...]`开始,并附加`zipWith(+)fibs(tail fibs)`.fibs的第一个元素是"0",尾部纤维的第一个元素是"10",所以下一个元素是"0 + 1 = 1"给你"[0,1,1 ...]",现在你得到了`zipWith ...`的第二个元素是`1 + 1 = 2`给你`[0,1,1,2 ......]`等等. (2认同)

ren*_*ith 24

根据定义,斐波纳契数列的每个项目都是前两个项的总和.将此定义放入lazy haskell给你这个!

fibo a b = a:fibo b (a+b)
Run Code Online (Sandbox Code Playgroud)

现在只需从0开始从fibo中取n个项目

take 10 (fibo 0 1)
Run Code Online (Sandbox Code Playgroud)

  • 这是一个美丽的函数,美丽是数学和编程中的一切。其简洁性和说服力是非凡的。它富有诗意,紧凑而富有意义。 (2认同)

yai*_*chu 20

扩展dtb的答案:

"简单"解决方案之间存在重要区别:

fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
Run Code Online (Sandbox Code Playgroud)

你指定的那个:

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)

简单的解决方案需要O(1.618 N N)时间来计算第N个元素,而您指定的那个需要O(N 2).这是因为您指定的那个考虑到计算fib nfib (n-1)(计算它需要)共享依赖性fib (n-2),并且可以计算一次以节省时间.O(N 2)用于N个O(N)个数字的加法.

  • 为什么不简单地说黄金比例(Phi)而不是不精确的`1.618`? (2认同)
  • @Zelphir:这将要求读者也熟悉黄金比例.准确性对于这个论点并不重要 (2认同)

Ric*_*lap 5

有许多不同的哈斯克尔算法斐波纳契数列在这里."天真"的实现看起来就像你追求的那样.


nic*_*jou 5

fibs :: [Integer]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)

首先,使用fibsand tail fibs,我们可以得到第三个元素:

fibs                        : [1, 1, ?
tail fibs                   : [1, ?
zipWith (+) fibs (tail fibs): [2, ?
Run Code Online (Sandbox Code Playgroud)

现在,我们知道第三个是 2,我们可以得到第四个:

fibs                        : [1, 1, 2, ?
tail fibs                   : [1, 2, ?
zipWith (+) fibs (tail fibs): [2, 3, ?
Run Code Online (Sandbox Code Playgroud)

现在是第 5 个:

fibs                        : [1, 1, 2, 3, ?
tail fibs                   : [1, 2, 3, ?
zipWith (+) fibs (tail fibs): [2, 3, 5, ?
Run Code Online (Sandbox Code Playgroud)

等等 ..