我刚刚开始使用VS2010学习F#,下面是我第一次尝试生成斐波纳契系列。我要做的是建立一个小于400的所有数字的列表。
let fabList =
let l = [1;2;]
let mutable a = 1
let mutable b = 2
while l.Tail < 400 do
let c = a + b
l.Add(c)
let a = b
let b = c
我的第一个问题是,在最后一个语句中,我在最后一行收到错误消息“表达式中此点或之前的不完整结构化构造”。我不明白我在这里做错了什么。
虽然这似乎是以相当有效的方式(从c ++ / C#程序员)构建列表的一种显而易见的方式,但从我对f#的了解很少,这似乎不是正确的方法做这个程序。这种感觉我是否正确?
答案 0 :(得分:45)
其他帖子告诉你如何使用递归函数编写while循环。这是使用F#中的Seq库的另一种方式:
// 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
如需解释,请在solution 2中引用F# for Project Euler Problems,其中前50个欧拉问题已解决。我想你会对这些解决方案感兴趣。
答案 1 :(得分:25)
首先,你正在使用let
,好像它是一个变异变量的声明,但事实并非如此。在F#中,let
用于声明一个新值(可能隐藏任何以前的同名值)。如果你想使用变异编写代码,那么你需要使用类似的东西:
let c = a + b // declare new local value
l.Add(c)
a <- b // mutate value marked as 'mutable'
b <- c // .. mutate the second value
您的代码的第二个问题是您试图通过向其添加元素来改变F#列表 - F#列表是不可变的,因此一旦您创建它们,就无法修改它们(特别是,没有{{1成员!)。如果你想用变异来写这个,你可以写:
Add
但是,正如其他人已经指出的那样,以这种方式编写代码并不是惯用的F#解决方案。在F#中,您将使用不可变列表和递归而不是循环(例如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
)。例如:
while
答案 2 :(得分:13)
let rec fibSeq p0 p1 = seq {
yield p0
yield! fibSeq p1 (p0+p1)
}
答案 3 :(得分:6)
这是使用序列表达式的无限尾递归解决方案。它非常高效,只需几秒钟即可产生第100,000个术语。 “yield”运算符就像C#的“收益率”和“收益率”一样。运算符可以被理解为“全部产生”,在C#中你必须做“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
这种方法类似于C#中的以下方法(使用while(true)循环而不是递归):
答案 4 :(得分:4)
是的,可变变量和while循环通常是一个很好的信号,表明你的代码功能不是很好。斐波纳契系列也不是从1,2开始 - 它以0,1或1,1开头,取决于你问的是谁。
我是这样做的:
let rec fabListHelper (a:int,b:int,n:int) =
if a+b < n then
a+b :: fabListHelper (b, a+b, n)
else
[];;
let fabList (n:int) = 0 :: 1 :: fabListHelper (0,1, n);;
(*> fabList 400;;
val it : int list = [0; 1; 1; 2; 3; 5; 8; 13; 21; 34; 55; 89; 144; 233; 377]*)
答案 5 :(得分:1)
此函数“fib”将返回不大于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;;
答案 6 :(得分:0)
这是.Net大师Scott Hanselman关于在F#中生成斐波那契系列的好文章
let rec fib n = if n < 2 then 1 else fib (n-2) + fib(n-1)
http://www.hanselman.com/blog/TheWeeklySourceCode13FibonacciEdition.aspx
它还与其他语言作为参考进行比较
答案 7 :(得分:0)
还有一种方法:
let rec fib = seq {
yield! seq {0..1}
yield! Seq.map (fun(a,b)->a+b) <| Seq.zip fib (Seq.skip 1 fib)
}
let a = fib |> Seq.take 10 |> Seq.toList
答案 8 :(得分:0)
一个有数组:
let fibonacci n = [|1..n|] |> Array.fold (fun (a,b) _ -> b, a + b) (0,1) |> fst
答案 9 :(得分:0)
使用汇总(折叠)的一种:
let fib n =
[1..n] |> List.fold (fun ac _ -> (ac |> List.take 2 |> List.sum) :: ac) [1;1] |> List.rev
答案 10 :(得分:-1)
Scott Hanselman的伟大解决方案并没有报告斐波那契序列的开始。
所以这是对他的解决方案的一个小改动,也报告了0。 我使用了从0到10的小列表来显示序列的前11项。
let nums=[0..10]
let rec fib n = if n < 1 then 0 else if n < 2 then 1 else fib (n-2) + fib(n-1)
let finres = List.map fib nums
printfn "%A" finres
我是f#的新手和无能,但仍然没有完全理解它的需要。但发现这是一个有趣的测试。
只是为了好玩:如果找到计算第n个斐波纳契数的Binet公式。 不幸的是,需要一些浮点函数来最终得到整数结果: [Binet的Fibonacci公式] [1]
http://i.stack.imgur.com/nMkxf.png
let fib2 n = (1.0 / sqrt(5.0)) * ( (((1.0 + sqrt(5.0)) /2.0)**n) - (((1.0 - sqrt(5.0)) /2.0)**n) )
let fib2res = fib2 10.0
System.Console.WriteLine(fib2res)
let strLine = System.Console.ReadLine()
对f#的快速而肮脏的翻译将如上所示。我相信其他人可以在风格和效率方面做出改进。该示例计算第10个数字。结果将是55。