Хвостовая рекурсия в Haskell

Я пытаюсь понять хвостовую рекурсию в Haskell. Думаю, я понимаю, что это такое и как работает, но я хотел бы убедиться, что не все испортил.

Вот "стандартное" определение факториала:

factorial 1 = 1
factorial k = k * factorial (k-1)

При запуске, например, факториала 3 , моя функция вызывает себя 3 раза (плюс-минус). Это могло бы создать проблему, если бы я хотел вычислить факториал 99999999, поскольку у меня могло бы быть переполнение стека. После того, как я доберусь до факториала 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 # может обнаруживать и преобразовывать хвостовые рекурсивные функции в циклы, я знаю (по крайней мере, то, что я слышал), что в настоящее время он этого не делает. Так что в настоящее время нет никакого смысла делать хвостовые функции рекурсивными.

Спасибо!

18
задан luqui 4 November 2010 в 01:09
поделиться