I am new to haskell and just learning the fun of functional programming. but have run into trouble right away with an implementation of the fibonacci function. Please find the code below.
--fibonacci :: Num -> [Num]
fibonacci 1 = [1]
fibonacci 2 = [1,1]
--fibonacci 3 = [2]
--fibonacci n = fibonacci n-1
fibonacci n = fibonacci (n-1) ++ [last(fibonacci (n-1)) + last(fibonacci (n-2))]
Rather awkward, I know. I can’t find time to look up and write a better one. Though I wonder what makes this so inefficient. I know I should look it up, just hoping someone would feel the need to be pedagogic and spare me the effort.
orangegoat’s answer and Sec Oe’s answer contain a link to probably the best place to learn how to properly write the fibonacci sequence in Haskell, but here’s some reasons why your code is inefficient (note, your code is not that different from the classic naive definition. Elegant? Sure. Efficient? Goodness, no):
Let’s consider what happens when you call
That expands into
In addition to concatenating two lists together with
++, we can already see that one place we’re being inefficient is that we calculatefibonacci 4twice (the two places we calledfibonacci (n-1). But it gets worst.Everywhere it says
fibonacci 4, that expands intoAnd everywhere it says
fibonacci 3, that expands intoClearly, this naive definition has a lot of repeated computations, and it only gets worse when n gets bigger and bigger (say, 1000).
fibonacciis not a list, it just returns lists, so it isn’t going to magically memoize the results of the previous computations.Additionally, by using
last, you have to navigate through the list to get its last element, which adds on top of the problems with this recursive definition (remember, lists in Haskell don’t support constant time random access–they aren’t dynamic arrays, they are linked lists).One example of a recursive definition (from the links mentioned) that does keep down on the computations is this:
Here,
fibsis actually a list, and we can take advantage of Haskell’s lazy evaluation to generatefibsandtail fibsas needed, while the previous computations are still stored inside of fibs. And to get the first five numbers, it’s as simple as:(Optionally, you can replace the first 0 with a 1 if you want the sequence to start at 1).