Generating Fibonacci numbers in Haskell?

前端 未结 11 1051
有刺的猬
有刺的猬 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: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
    

提交回复
热议问题