F#使用match创建Fibonacci序列的递归函数

时间:2013-10-17 01:10:48

标签: function f# fibonacci

我试图创建一个利用match来创建Fibonacci序列的递归函数。我让Euler2工作,但是在Euler2a中,我试图让整个函数自包含,除了迭代约束,j。

Euler2a必须如何改变才能提供序列?

任何指针都非常受欢迎。 :)

Euler2的结果

  

val Euler2:list:int list - > i:int - > j:int - > int list

     

val z:int list = [1; 2; 3; 5; 8; 13; 21; 34; 55; 89]

Euler2a的结果

  

val Euler2a:j:int - > (int list - > int - > int - > int list)

     

val z2:(int list - > int - > int - > int list)

Euler2

let rec Euler2 (list: int list) i j =
    match i with
    | 1 | 2         ->  Euler2 list (i+1) j
    | _ when (i<=j) ->  let newList = list @ [list.[list.Length - 1] + list.[list.Length - 2]]
                        Euler2 newList (i+1) j
    | _             ->  list

let z = Euler2 [1;2] 1 10

Euler2

let rec Euler2a (j:int) =
    let i = 1
    let list = [1;2]
    let rec Euler2b (list: int list) i j =
        match i with
        | 1 | 2         ->  Euler2b list (i+1) j
        | _ when (i<=j) ->  let newList = list @ [list.[list.Length - 1] + list.[list.Length - 2]]
                            Euler2b newList (i+1) j
        | _             ->  list
    Euler2b

let z2 = Euler2a 10

2 个答案:

答案 0 :(得分:4)

你的Euler2a返回值Euler2b,它是一个带有列表和2个整数参数的函数。您需要通过更改

中的行来实际提供参数
Euler2b

Euler2b list i j

以便将参数提供给函数。一切正常。

答案 1 :(得分:4)

除了Euler2b的{​​{1}}主体对内部函数Euler2a的递归调用格式的直接问题,John's answer地址存在与采用的方法相关的不太明显的问题。

  • 您的实现使用F# list作为基础数据结构。虽然它允许解决Project Euler Problem 2,但它更像是一个数组,而不是惯用的F#列表。表达式list @ [list.[list.Length - 1] + list.[list.Length - 2]]在计算上非常昂贵,不仅使用索引器list.[i],而且还来自追加运算符@,后者在每次迭代时完全删除当前列表并重新创建新的,一个元素更长,创建垃圾收集的不必要压力。 一个惯用的F#使用列表将从左边开始,并在最后一步上反转,如下所示:

    let euler2c len =
        let rec inner (list: int list) i len =
            match list with
            | l::p::tail when (i < len) -> inner ((l + p)::l::p::tail) (i+1) len
            | _  ->  List.rev list
        inner [2;1] 2 len
    
  • 具有一定长度的Fibonacci数列表不便于解决原始问题,因为解决方案应该基于最后一个元素的值,这可能需要额外的参数/条件。更惯用的是从list切换到F# sequence到懒惰地表示任意长度的斐波那契序列。使用库函数Seq.unfold允许以下简洁的单线程实现:

    let fibnums = Seq.unfold (fun(curr,next) -> Some(curr,(next,curr+next)))(1,2)
    

    现在fibnums类型seq<int>允许使用库函数和组合器以惯用方式进行操作。特别是,使最后一个元素不超过4000000的序列可以表示为fibs |> Seq.takeWhile ((>=) 4000000)