2012-04-11 1 views
2

В соответствии с документацией MSDN при записи рекурсивной функции использование аргумента аккумулятора делает функцию tail рекурсивной, что экономит пространство стека. Я использую два примера, приведенного на сайте MSDN для расчета суммы всех чисел в list-Почему функция хвостовой рекурсии не работает для ввода, для которого нормальная рекурсивная функция выполняется успешно?

первый без хвоста recursion-

let rec Sum myList = 
    match myList with 
    | [] -> 0 
    | h::t -> h + Sum t 

и теперь с хвостом recursion-

let Sumtail list = 
    let rec loop list acc = 
     match list with 
     | h::t -> loop t acc + h 
     | [] -> acc 
    loop list 0 

и работает как с функциями [1..100000]. Функция Sum успешно вычисляет сумму этого списка, но дает исключение stackoverflow, если я передаю [1..1000000] , но вторая функция Sumtail терпит неудачу при [1..100000], тогда как она должна давать более высокую производительность, чем первая функция, поскольку использует хвостовую рекурсию. Существуют ли другие факторы, влияющие на рекурсивную функцию?

+3

Я считаю, что вы что-то недопонимаете - использование аргумента аккумулятора не делает функцию хвостовой рекурсивной. Аргумент аккумулятора - это метод накопления значений при использовании хвостовой рекурсивной функции. Это своего рода метод, который обычно приходит с хвостовым рекурсивом, но он не определяет хвост-рекурсивный. –

ответ

10

Ваша вторая функция не является хвостовой рекурсией, поскольку loop t acc + h анализируется как (loop t acc) + h, что делает + стать последней операцией на loop.

Измените loop t acc + h на loop t (acc + h), чтобы функция получило функцию tail-recursive.

+0

это правильно, но я не могу отметить его справа и (еще 6 минут). Что это делает? – Kapil

+2

Оператор '+' должен применяться к возвращаемому значению из цикла, поэтому компилятор не может использовать хвостовую рекурсию, которая забудет состояние h для каждого рекурсивного вызова. Рекурсия хвоста работает, если состояние можно забыть - если мы знаем, что возвращаемое значение в противном случае было бы возвращено через все фреймы стека без изменений. –