Я пытаюсь понять хвостовую рекурсию в Хаскеле.Я думаю, что понимаю, что это такое и как это работает, но я хотел бы убедиться, что я не напутал.
Вот «стандартное» факториальное определение:
factorial 1 = 1
factorial k = k * factorial (k-1)
При запуске, например, factorial 3
, моя функция будет вызывать себя 3 раза (дать или взять).Это может создать проблему, если я хочу вычислить факториал 99999999, поскольку у меня может быть переполнение стека.После того как я доберусь до factorial 1 = 1
, мне придется «вернуться» в стеке и умножить все значения, поэтому у меня есть 6 операций (3 для вызова самой функции и 3 для умножения значений).
ТеперьЯ представляю вам еще одну возможную факториальную реализацию:
factorial 1 c = c
factorial k c = factorial (k-1) (c*k)
Эта тоже рекурсивная.Это будет называть себя 3 раза.Но у него нет проблемы с тем, чтобы по-прежнему приходиться «возвращаться» для вычисления умножения всех результатов, поскольку я уже передаю результат в качестве аргумента функции.
Это для чегоЯ понял, что такое Tail Recursion.Теперь он кажется немного лучше, чем первый, но вы все равно можете легко переполняться стеками.Я слышал, что компилятор Haskell преобразует функции Tail-Recursive в циклы for за кулисами.Я полагаю, это является причиной того, что выполнение хвостовых рекурсивных функций окупается?
Если это причина, то совершенно не нужно пытаться делать функции хвостовыми рекурсивными, если компилятор не собирается делать это умнотрюк - я прав?Например, хотя в теории компилятор C # мог обнаруживать и преобразовывать хвостовые рекурсивные функции в циклы, я знаю (по крайней мере, то, что я слышал), что в настоящее время он этого не делает.Таким образом, в настоящее время абсолютно бессмысленно делать функции хвостовыми рекурсивными.Это так?
Спасибо!