Нет условия завершения цикла. Чтобы исправить код:
let rec somme1 x =
if x <= 0
then 0
else if ((x mod 3) = 0) or ((x mod 5) = 0)
then x + (somme1 (x-1))
else somme1 (x-1);;
somme1 1000;;
Чтобы улучшить свой код, вы должны сделать свою функцию хвостовой рекурсией.
let rec somme2 x accum =
if x <= 0
then accum
else if ((x mod 3) = 0) or ((x mod 5) = 0)
then somme2 (x-1) (accum+x)
else somme2 (x-1) accum
somme2 1000 0;;
Разница между двумя версиями заключается в том, что в случае хвостовой рекурсии результаты рекурсивного вызова точно такие же, как и результат функции, поэтому не требуется сохранять промежуточное состояние для завершения вычисления после того, как рекурсивная функция будет выполнена. называется. Когда вы вызываете somme1 1000;;, поскольку (1000 mod 5 == 0) or (1000 mod 3 == 0) оценивает true, вы получаете рекурсивный вызов 1000 + (somme1 999), для завершения которого требуется рекурсивный вызов 999 + (somme1 998). Компилятор должен хранить числа 1000 и 999 в стеке до тех пор, пока somme1 не завершит выполнение, чего он не делает (нет условия завершения), поэтому ваш стек заполняется, пытаясь сохранить 1000 + (999 + (996 + (995 + ....
Это будет эквивалентно ((((0 + 1000) + 999) + 996) + 995) + ..., но в этом случае нет промежуточных значений, необходимых для работы над результатом рекурсивных вызовов (то есть возвращаемое значение рекурсивного вызова совпадает с возвращаемым значением самой функции), поэтому дополнительное пространство стека не требуется. Второй вариант работает так. Если бы у него была та же ошибка, что и у первого, он бы не исчерпал стек, а просто продолжал бы выполняться бесконечно. Это считается улучшением. :-)
person
Aidan Cully
schedule
23.12.2009