所以我创建了这个函数来计算某个数字的fib,非常标准:
fib 0 = 0
fib 1 = 1
fib x = fib(x-1) + fib(x-2)
但是现在我希望能够计算到某个数字的纤维并将每个答案添加到列表中。例如,如果我要计算6的纤维,那么我应该得到[0,1,1,2,3,5,8]的列表
答案 0 :(得分:4)
@milad zahedi的答案中的fibs
版本是用于生成无限序列的经典Haskell方法,尽管对于刚学习Haskell的人来说它可能太聪明了一半。这是另一种提出正确答案的方法。
在Haskell中递归生成列表的一种非常标准的方法是编写如下内容:
countDownFrom 0 = []
countDownFrom n = n : countDownFrom (n-1)
这里,第二行通过生成下一个元素n
并将其附加到列表的其余部分"来生成列表,通过递归调用{{1}生成}}。当我们达到零时,第一行提供基本情况,因此我们不会永远计数(假设我们以非负整数开始 - 否则,就是!)。
计算向上需要稍微区别一点,因为:
countDownFrom (n-1)
没有共同的基本情况 - 它取决于我们想要计算的高度。在Haskell中有很多处理这个的方法,但是一个非常常见的模式是生成一个无限列表并从头开始采用有限数量的元素:
countUpFrom n = n : countUpFrom (n+1)
其中countUpLen n = take n (countUpFrom 1)
where countUpFrom n = n : countUpFrom (n+1)
生成countUpLen 5
。
尽管如此,我们可以为您的Fibonacci序列使用类似的模式。但是,如果我们试着写:
[1,2,3,4,5]
我们遇到了一些问题。例如,如果fibs n = take n (allFibs 0)
allFibs x = x : allFibs ???
应该生成从1开始的序列,则不清楚它是否应该生成allFibs 1
或[1,1,2,3,...]
- 换句话说,哪1个是我们从?开始。
修复此问题需要一些技巧,但是一旦你看到它,它就显而易见了。让我们说我们需要生成从[1,2,3,5,...]
开始的Fibonacci序列的一部分。如果我们跟踪下一个两个数字(2和3),那将很容易 - 我们吐出2并将其附加到序列其余部分的头部,将由两个数字3和5(从2 + 3计算)生成。换句话说,对于这个特定情况,我们有:
[2,3,5,...]
更一般地说,我们可以写:
allFibs 2 3 = 2 : allFibs 3 (2+3)
解释是allFibs a b = a : allFibs b (a+b)
生成"斐波那契序列的其余部分,以allFibs a b
和a
"开头。
然后,我们可以编写最终解决方案:
b
的工作原理如下:
fibs :: Int -> [Int]
fibs n = take n (allFibs 0 1)
where allFibs a b = a : allFibs b (a+b)
答案 1 :(得分:2)
这是一个很好的解决方案
fibs :: [Integer]
fibs = 0:1:zipWith (+) fibs (tail fibs)
但如果我们改进您的解决方案,我们会得到:
fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib(n-1) + fib (n-2)
fibs :: [Integer]
fibs = fmap fib [0..]
效率低于第一种解决方案。