Generating Fibonacci numbers in Haskell?

前端 未结 11 974
有刺的猬
有刺的猬 2020-11-29 18:35

In Haskell, how can I generate Fibonacci numbers based on the property that the nth Fibonacci number is equal to the (n-2)th Fibonacci number plus the (n-1)th Fibonacci numb

相关标签:
11条回答
  • 2020-11-29 19:05

    Here's a different and simpler function that calculates the n'th Fibonacci number:

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

    The implementation you are referring to relays on some observations about how values in Fibonacci relate to each other (and how Haskell can define data structures in terms of themselfs in effect creating infinite data structures)

    The function in your question works like this:

    Assume you already had an infinite list of the Fibonacci numbers:

       [ 1, 1, 2, 3, 5,  8, 13, .... ]
    

    The tail of this list is

       [ 1, 2, 3, 5, 8, 13, 21, .... ]
    

    zipWith combines two lists element by element using the given operator:

       [ 1, 1, 2, 3,  5,  8, 13, .... ]
    +  [ 1, 2, 3, 5,  8, 13, 21, .... ]
    =  [ 2, 3, 5, 8, 13, 21, 34, .... ]
    

    So the infinite list of Fibonacci numbers can be calculated by prepending the elements 1 and 1 to the result of zipping the infinite list of Fibonacci numbers with the tail of the infinite list of Fibonacci numbers using the + operator.

    Now, to get the n'th Fibonacci number, just get the n'th element of the infinite list of Fibonacci numbers:

    fib n = fibs !! n
    

    The beauty of Haskell is that it doesn't calculate any element of the list of Fibonacci numbers until its needed.

    Did I make your head explode? :)

    0 讨论(0)
  • 2020-11-29 19:05

    There are a number of different Haskell algorithms for the Fibonacci sequence here. The "naive" implementation looks like what you're after.

    0 讨论(0)
  • 2020-11-29 19:06

    using iterate

    fibonaci = map fst (iterate f (0,1)) where f (x,y) = (y,x+y)
    

    using

    take 10 fibonaci
    
    [0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]
    
    0 讨论(0)
  • 2020-11-29 19:07

    I was doing the homework6 of CIS194 and find that you could write this way. Computing the first n elements requires only O(n) addition operations.

    fibs2 :: [Integer]
    fibs2 = [0, 1] ++ [fibs2 !! (n-1) + fibs2 !! (n-2) | n <- [2..]]
    
    0 讨论(0)
  • 2020-11-29 19:08

    The definition of fibonaci(n) is:

    fibonacci (n) = fibonacci (n-1) + fibonacci (n-2)

    The naive implementation in Haskell

    fibonacci :: Integer -> Integer
    fibonacci 0 = 1
    fibonacci 1 = 1
    fibonacci x = fibonacci (x-1) + fibonacci (x-2)
    

    All formulas can be traced back to this definition, some which run very quickly, some of which run very slowly. The implementation above has O(n) = 2^n

    In the spirit of your question, let me remove the use of lists and give you something that runs in O(n) I.e. let's not hold all the fibonaccis from 0 to n in a list.

    If we have a triple (a tuple with three members) that looks like:

    (n, fibonacci[n-1], fibonacci[n])

    Remembering the initial definition, we can calculate the next triple from the last triple:

    (n+1, fibonacci[n], fibonacci[n-1] + fibonacci[n]) = (n+1, fibonacci[n], fibonacci[n+1])

    And the next triple from the last triple: (n+2, fibonacci[n+1], fibonacci[n] + fibonacci[n+1]) = (n+1, fibonacci[n+1], fibonacci[n+2])

    And so on...

    n = 0 => (0,0,1) 
    n = 1 => (1,1,1) - calculated from the previous triple
    n = 2 => (2,1,2) - calculated from the previous triple
    n = 3 => (3,2,3) - calculated from the previous triple
    n = 4 => (4,3,5) - calculated from the previous triple
    n = 5 => (5,5,8) - calculated from the previous triple
    

    Let's implement this in Haskell and use self explanatory variable names:

    nextTripleIfCurrentNIsLessThanN :: (Int, Integer, Integer) -> Int -> (Int, Integer, Integer)
    nextTripleIfCurrentNIsLessThanN (currentN, x, y) n = if currentN < n
    then nextTripleIfCurrentNIsLessThanN (currentN + 1, y, x + y) n
    else (currentN, x, y)
    
    thirdElementOfTriple :: (x,y,z) -> z
    thirdElementOfTriple (x,y,z) = z
    
    fibonacci :: Int -> Integer
    fibonacci n = thirdElementOfTriple (nextTripleIfCurrentNIsLessThanN (0,0,1) n)
    

    This will work in O(n) [It is mildly quadratic which shows up in large numbers. The reason for that is that adding big numbers is more costly than adding small ones. But that's a separate discussion about model of computation.]

    fibonacci 0
    1
    fibonacci 1
    1
    fibonacci 2
    2
    fibonacci 3
    3
    fibonacci 4
    5
    fibonacci 5
    8
    fibonacci 5000
    6276302800488957086035253108349684055478528702736457439025824448927937256811663264475883711527806250329984690249846819800648580083040107584710332687596562185073640422286799239932615797105974710857095487342820351307477141875012176874307156016229965832589137779724973854362777629878229505500260477136108363709090010421536915488632339240756987974122598603591920306874926755600361865354330444681915154695741851960071089944015319300128574107662757054790648152751366475529121877212785489665101733755898580317984402963873738187000120737824193162011399200547424034440836239726275765901190914513013217132050988064832024783370583789324109052449717186857327239783000020791777804503930439875068662687670678802914269784817022567088069496231111407908953313902398529655056082228598715882365779469902465675715699187225655878240668599547496218159297881601061923195562143932693324644219266564617042934227893371179832389642895285401263875342640468017378925921483580111278055044254198382265567395946431803304304326865077742925818757370691726168228648841319231470626
    
    0 讨论(0)
  • 2020-11-29 19:12

    going by the definition, every item of the fibonacci series is the sum of the previous two terms. putting this definition in to lazy haskell gives u this!

    fibo a b = a:fibo b (a+b)
    

    now just take n items from fibo starting with 0,1

    take 10 (fibo 0 1)
    
    0 讨论(0)
提交回复
热议问题