【问题标题】:How to diagnose source of failure in F# interactive如何在 F# 交互中诊断故障源
【发布时间】:2010-03-02 00:49:31
【问题描述】:

我正在通过 Project Euler 学习 F# 的原理,并多次遇到以下问题。我编写了一个函数,在 F# 交互窗口中运行它,程序就挂在那里了。我怀疑该功能失败了,但我没有收到任何可以帮助我找出问题所在的重要错误消息。有什么方法可以调试在 F# 交互中运行的程序?
作为说明,这里有一个来自问题 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);;

【问题讨论】:

    标签: debugging f# f#-interactive


    【解决方案1】:

    如果你有例如运行“windows 任务管理器”,您会看到您的 CPU 在挂起时完全耗尽。你刚刚创造了太多的工作;你需要一个更有效的算法。在 F# 交互中按“中断”键(在 Visual Studio 的 FSI 窗口中按 Ctrl-.)停止处理。

    如果大哦不清楚,您可以考虑添加一些打印以显示正在完成的工作量。例如

    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 以了解正在发生的事情。

    【讨论】:

    • 谢谢布赖恩。 Big-O 很清楚,我知道我的算法效率很低,但我不确定问题是性能不佳还是发生了异常。我认为应该归咎于表现:)
    • 是的,如果有异常,您会得到反馈 - 尝试一下(在某处添加“raise(new Exception("boom"))”,看看 Interactive 的行为如何)。
    • 另外,根据您的回答,我认为在 Interactive 中运行时无法使用断点或观看之类的东西?
    • 我觉得把代码放到工程里调试工程比较容易调试。
    【解决方案2】:

    程序挂起通常有两个原因:

    1. 死循环

    2. 低效的代码

    在像 F# 这样的 FP 语言中,您很少会编写一个永远运行的死循环。

    这是我在做欧拉时的调试混乱:

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

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

    正如 Brain 所说,您需要更高效的 NumberOfDivisors 实现: http://en.wikipedia.org/wiki/Euler%27s_totient_function

    【讨论】:

    • 感谢totient函数的链接,很有意思。
    猜你喜欢
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-30
    • 1970-01-01
    相关资源
    最近更新 更多