10

I have been trying to implement a list of Fibonacci number sequence from 0 to n without using the lazy zipwith method. What I have so far is code that returns a list from n to 1. Is there any way I can change this code so it returns the list from 0-n at all?

Example:

fib_seq 4 = [3,2,1,1] 
-- output wanted: [1,1,2,3]

If there is not a way to do what I want the code to do, is there a way to just return the list of Fibonacci numbers taking in a number say again 4 it would return [0, 1, 1, 2].

fib_seq :: Int -> [Int]
fib_seq 0 = [0]
fib_seq 1 = [1]
fib_seq n = sum (take 2 (fib_seq (n-1))) : fib_seq (n-1)
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Jimbhoy
  • 195
  • 8
  • 1
    better to use let, `fib_seq2 n = let { fs = fib_seq2 (n-1) } in sum (take 2 fs) : fs`. compare the speeds for `fib_seq 30`. – Will Ness Feb 13 '21 at 07:40

4 Answers4

6

Another way you could choose to implement the fib numbers is the use of a helper function then a function on it's own that will produce the infinite list of fib numbers, or you could use take 10 fibs and the output for this would be the first 10 fib numbers. My function is definitely not the fastest way to work out the fib numbers infintely that would be with the zipWith function, but you are not using that here so here is my way to implement it without zipWith.

for example take 10 fibs would return: [0,1,1,2,3,5,8,13,21,34]

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)   

fibs :: [Int]
fibs = (map fib [0..])
program.exe
  • 451
  • 4
  • 12
  • this is what i was looking for as this allows me to choose if i want the infinite list or if i want to choose the number of fib numbers to print thanks for the help!!! – Jimbhoy Feb 15 '21 at 09:27
  • no problem glad this helped, there are some other good answers within this question make sure you have had a read at them all and understand, my version will be very slow for calling larger fib numbers do to the number of recursive calls that the program needs to make. – program.exe Feb 15 '21 at 09:29
5

It is often the case that you can solve a problem by considering a slightly more general version of it.

Say we want the infinite Fibonacci list starting with two prescribed initial values a and b. There is an obvious recursive solution:

$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
 ...
 λ> 
 λ> aux_fib a b = a : (aux_fib b (a+b))
 λ> 
 λ> take 4 (aux_fib 1 1)
 [1,1,2,3]
 λ> 

And so:

 λ> 
 λ> fib_seq n = take n (aux_fib 1 1)
 λ> 
 λ> fib_seq 4
 [1,1,2,3]
 λ> 

Note: camel case is regarded as more idiomatic in Haskell, so it would be more like auxFib and fibSeq.

jpmarinier
  • 4,427
  • 1
  • 10
  • 23
2

If you wanted to have the list start from 0 you could use a helper function and then use this helper function within your fib_seq (which i recommend you change to Camel case so like fibSeq, standard haskell notation)

Ok so the functions as follow fibSeq 7 would return [0,1,1,2,3,5,8]:

fibHelp :: Int -> Int -> [Int]
fibHelp x y = x : (fibHelp y (x+y))

fibSeq :: Int -> [Int]
fibSeq n = take n (fibHelp 0 1)
tDownUnder
  • 149
  • 6
1

It feels a bit like cheating, but you could use the closed formula for the Fibonacci sequence like this:

fib n = (phi^n - psi^n) / sqrt 5
  where
    phi = (1 + sqrt 5) / 2
    psi = (1 - sqrt 5) / 2

fibSeq n = fib <$> [1 .. n]

Otherwise the Haskell Wiki has many more implementation variants to chose from. For example very succinctly

fibs = 0 : 1 : next fibs
  where
    next (a : t@(b:_)) = (a+b) : next t
michid
  • 10,536
  • 3
  • 32
  • 59
  • 1
    The closed formula is going to produce extremely bad precision quite early on. The matrix exponentiation by squaring approach will work much better. – dfeuer Feb 14 '21 at 06:06
  • we'd need some form of arbitrary fixed precision numbers to make it work, perhaps? we can approximate the magnitude of `fib n` as `phi^n`, so we know the needed number of digits in advance, and just use twice as many to be on the safe side. question is, what would be the complexity of such a thing. :) @dfeuer – Will Ness Feb 14 '21 at 14:10
  • @WillNess, I can't tell you, but it seems almost certain not to be better than multiplication by squaring. – dfeuer Feb 15 '21 at 15:05
  • @dfeuer my feeling exactly. :) – Will Ness Feb 15 '21 at 15:07
  • By which I mean exponentiation by squaring. – dfeuer Feb 15 '21 at 16:16
  • 1
    Related to the matrix form, since φ is an algebraic number, you can avoid the precision issues by representing it exactly as the implicit root of a polynomial with rational (or in this case integer) coefficients, namely x² − x − 1, and then there’s a very pretty implementation of the closed-form formula, which this comment box is too small to contain. It’s not fast either haha – Jon Purdy Feb 17 '21 at 02:15