如何诊断F#交互中的失败源

时间:2010-03-02 00:49:31

标签: debugging f# f#-interactive

我正在通过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);;

2 个答案:

答案 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)

程序通常由于两个原因而挂起:

  1. 死循环

  2. 效率低下的代码

  3. 在FP语言中,就像F#一样,你写一个永远运行的死循环是非常罕见的。

    这是我在执行Euler时的调试问题:

    1. 使用小测试用例测试每个函数。编写函数后,请对其进行测试。一个算法不太可能适用于1 - 100并且在101处失败,尤其是当您使用像F#这样的“安全”语言时。

    2. 估算算法的运行时间。如果它是O(n ^ 2),则n = 10000可能是您的算法的上限。在这个问题中,答案是超过70M,蛮力O(n ^ 2)算法永远运行。 F#interactive提供#time来分析程序的运行行为,例如运行时和垃圾收集数。

    3. 正如Brain所说,你需要一个更有效的NumberOfDivisors实现: http://en.wikipedia.org/wiki/Euler%27s_totient_function