Как диагностировать источник сбоя в F # интерактив - PullRequest
3 голосов
/ 02 марта 2010

Я изучаю веревки F # через Project Euler и столкнулся с следующей проблемой несколько раз. Я пишу функцию, запускаю ее в интерактивном окне 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);;

Ответы [ 2 ]

3 голосов
/ 02 марта 2010

Если у вас есть, например, «Диспетчер задач Windows» работает, и вы увидите, что ваш ЦП работает с полной нагрузкой, пока устройство зависло. Вы только что создали слишком много работы; вам нужен более эффективный алгоритм. Нажмите клавишу «прерывание» в интерактивном режиме F # (Ctrl-. В окне FSI в Visual Studio), чтобы остановить обработку.

Если биг-о не ясно, вы можете добавить несколько распечаток, чтобы показать, сколько работы уже сделано. Э.Г.

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 с большими и большими числами, чтобы понять, что происходит.

2 голосов
/ 02 марта 2010

Программа зависает обычно по двум причинам:

  1. мертвая петля

  2. неэффективный код

На языке FP, например на F #, очень редко вы пишете мертвый цикл, который выполняется вечно.

Это моя проблема отладки при выполнении Эйлера:

  1. проверка каждой функции с использованием небольших тестовых случаев. Когда вы написали функцию, протестируйте ее. Маловероятно, что алгоритм работает для 1 - 100 и не работает на 101, особенно когда вы используете «безопасный» язык, такой как F #.

  2. оцените время работы вашего алгоритма. Если это O (n ^ 2), тогда n = 10000 может быть верхним пределом для вашего алгоритма. В этой задаче ответ более 70M, алгоритм грубой силы O (n ^ 2) работает вечно. А интерактивный F # предоставляет #time для профилирования поведения вашей программы, например времени выполнения и количества сборок мусора.

Как сказал Брейн, вам нужна более эффективная NumberOfDivisors реализация: http://en.wikipedia.org/wiki/Euler%27s_totient_function

...