Generating Fibonacci series in F#

后端 未结 11 1921
南方客
南方客 2020-12-31 02:58

I\'m just starting to learn F# using VS2010 and below is my first attempt at generating the Fibonacci series. What I\'m trying to do is to build a list of all numbers less

相关标签:
11条回答
  • 2020-12-31 03:31

    Here's an infinite tail-recursive solution using sequence expressions. It's quite efficient, producing the 100,000th term in just a few seconds. The "yield" operator is just like C#'s "yield return", and the "yield!" operator may be read as "yield all", where in C# you would have to do "foreach item ... yield return item".

    https://stackoverflow.com/questions/2296664/code-chess-fibonacci-sequence/2892670#2892670

    let fibseq =    
        let rec fibseq n1 n2 = 
            seq { let n0 = n1 + n2 
                  yield n0
                  yield! fibseq n0 n1 }
        seq { yield 1I ; yield 1I ; yield! (fibseq 1I 1I) }
    
    let fibTake n = fibseq |> Seq.take n //the first n Fibonacci numbers
    let fib n = fibseq |> Seq.nth (n-1) //the nth Fibonacci number
    

    This approach is similar to the following in C# (which uses a while(true) loop instead of recursion):

    Finding Fibonacci sequence in C#. [Project Euler Exercise]

    0 讨论(0)
  • 2020-12-31 03:33

    Other posts tell you how to write the while loop using recursive functions. This is another way by using the Seq library in F#:

    // generate an infinite Fibonacci sequence
    let fibSeq = Seq.unfold (fun (a,b) -> Some( a+b, (b, a+b) ) ) (0,1)
    // take the first few numbers in the sequence and convert the sequence to a list
    let fibList = fibSeq |> Seq.takeWhile (fun x -> x<=400 ) |> Seq.toList
    

    for explanation, please ref solution 2 in F# for Project Euler Problems, where the first 50 Euler problems are solved. I think you will be interested in these solutions.

    0 讨论(0)
  • 2020-12-31 03:34

    One using aggregation (fold):

    let fib n = 
      [1..n] |> List.fold (fun ac _ -> (ac |> List.take 2 |> List.sum) :: ac) [1;1] |> List.rev
    
    0 讨论(0)
  • 2020-12-31 03:40

    First of all, you're using let as if it was a statement to mutate a variable, but that's not the case. In F#, let is used to declare a new value (which may hide any previous values of the same name). If you want to write code using mutation, then you need to use something like:

    let c = a + b  // declare new local value
    l.Add(c)  
    a <- b   // mutate value marked as 'mutable'
    b <- c   // .. mutate the second value
    

    The second issue with your code is that you're trying to mutate F# list by adding elements to it - F# lists are immutable, so once you create them, you cannot modify them (in particular, there is no Add member!). If you wanted to write this using mutation, you could write:

    let fabList = 
      // Create a mutable list, so that we can add elements 
      // (this corresponds to standard .NET 'List<T>' type)
      let l = new ResizeArray<_>([1;2])
      let mutable a = 1
      let mutable b = 2
      while l.[l.Count - 1] < 400 do
        let c = a + b
        l.Add(c) // Add element to the mutable list
        a <- b
        b <- c
      l |> List.ofSeq // Convert any collection type to standard F# list
    

    But, as others already noted, writing the code in this way isn't the idiomatic F# solution. In F#, you would use immutable lists and recursion instead of loops (such as while). For example like this:

    // Recursive function that implements the looping
    // (it takes previous two elements, a and b)
    let rec fibsRec a b =
      if a + b < 400 then
        // The current element
        let current = a + b
        // Calculate all remaining elements recursively 
        // using 'b' as 'a' and 'current' as 'b' (in the next iteration)
        let rest = fibsRec b current  
        // Return the remaining elements with 'current' appended to the 
        // front of the resulting list (this constructs new list, 
        // so there is no mutation here!)
        current :: rest
      else 
        [] // generated all elements - return empty list once we're done
    
    // generate list with 1, 2 and all other larger fibonaccis
    let fibs = 1::2::(fibsRec 1 2)
    
    0 讨论(0)
  • 2020-12-31 03:40

    This function "fib" will return a list of Fibonacci numbers that are not greater than 500

    let rec fib a b =
        let current = a + b
        match current with
        | _ when current >= 500 -> []
        | _ -> current :: fib b current 
    
    let testFib = fib 1 2;;
    
    0 讨论(0)
  • 2020-12-31 03:41
    let rec fibSeq p0 p1 = seq {
        yield p0
        yield! fibSeq p1 (p0+p1)
    }
    
    0 讨论(0)
提交回复
热议问题