2012-04-11 11 views
2

MSDNドキュメントに従って、再帰関数を記述する際には、accumulator引数を使用すると関数の末尾が再帰的になり、スタック領域が節約されます。 私は尾なしリスト -通常の再帰関数が正常に実行される入力に対して、なぜテール再帰関数が失敗するのですか?

最初にすべての数字の合計を計算するMSDNのサイトで与えられた2例を使用していますが

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

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

と今をrecursion-

であり、入力が[1..100000]の両方の関数を実行しています。 関数Sumは、このリストの合計を正常に計算しますが、[1..1000000] を渡したが、2番目の関数Sumtail[1..100000]で失敗しますが、テール再帰を使用するため、最初の関数の方が優れています。 再帰関数に影響する他の要因はありますか?

+3

私は何かを誤解していると思います。アキュムレータの引数を使用しても、テール再帰的な関数にはなりません。アキュムレータ引数は、テール再帰関数を使用しているときに値を累積するための手法です。これは通常、tail-recursiveを使用するテクニックですが、tail-recursiveは定義しません。 –

答えて

10

loop t acc + h(loop t acc) + hと解釈され、+loopの最後の操作になるため、2番目の関数はテール再帰的ではありません。

loop t acc + hからloop t (acc + h)に変更すると、テール再帰的になります。

+0

thats右だけど、私はそれに右のans(まだ6分行く)をマークすることはできません。それはどんな違いがありますか? – Kapil

+2

'+'演算子は、ループからの戻り値に適用する必要があります。したがって、コンパイラは各再帰呼び出しのhの状態を忘れるテール再帰を使用できません。テール再帰は、状態が忘れられても動作します。そうしなければ、返り値は変更されずにすべてのスタックフレームを通して返されます。 –