我正在通过Project Euler学习F#的绳索,并且几次遇到以下问题。我编写了一个函数,在F#交互式窗口中运行它,程序挂起。我怀疑该功能失败了,但我没有得到任何重要的错误信息,这将有助于我弄清楚出了什么问题。有没有办法调试在F#interactive中运行的程序?
作为一个例子,这是一个例子,来自问题12. FindFirstTriangle(0,0,100)运行正常,但当除数大约为150时,事情就会卡住。
注意:这不是关于这段代码的错误,而是关于如何找出出错的地方!
let NumberOfDivisors n =
[1 .. n] |> List.filter (fun i -> n % i = 0) |> List.length;;
let HasMoreThanDDivisors n d =
if NumberOfDivisors n >= d then
true
else
false
let rec FindFirstTriangle (index, number, divisors) =
if HasMoreThanDDivisors number divisors then
number
else
let nextIndex = index + 1
let nextNumber = number + index
FindFirstTriangle (nextIndex, nextNumber, divisors);;
答案 0 :(得分:3)
如果您有例如“Windows任务管理器”运行你会看到你的CPU在挂起的时候运行平稳。你刚刚创造了太多的工作;你需要一个更有效的算法。按F#interactive中的'interrupt'键(在Visual Studio的FSI窗口中按Ctrl-键)停止处理。
如果大哦不清楚,你可以考虑添加一些打印来显示正在做多少工作。 E.g。
let NumberOfDivisors n =
printf "%d" n // added
seq {1 .. n} |> Seq.filter (fun i -> n % i = 0) |> Seq.length;;
let HasMoreThanDDivisors n d =
if NumberOfDivisors n >= d then
true
else
false
let rec FindFirstTriangle (index, number, divisors) =
printfn "" // added
if HasMoreThanDDivisors number divisors then
number
else
let nextIndex = index + 1
let nextNumber = number + index
FindFirstTriangle (nextIndex, nextNumber, divisors);;
然后使用越来越多的数字运行FindFirstTriangle以了解正在发生的事情。
答案 1 :(得分:2)
程序通常由于两个原因而挂起:
死循环
效率低下的代码
在FP语言中,就像F#一样,你写一个永远运行的死循环是非常罕见的。
这是我在执行Euler时的调试问题:
使用小测试用例测试每个函数。编写函数后,请对其进行测试。一个算法不太可能适用于1 - 100并且在101处失败,尤其是当您使用像F#这样的“安全”语言时。
估算算法的运行时间。如果它是O(n ^ 2),则n = 10000可能是您的算法的上限。在这个问题中,答案是超过70M,蛮力O(n ^ 2)算法永远运行。 F#interactive提供#time
来分析程序的运行行为,例如运行时和垃圾收集数。
正如Brain所说,你需要一个更有效的NumberOfDivisors
实现:
http://en.wikipedia.org/wiki/Euler%27s_totient_function