マイクロソフトのサイトから抜粋1
要素のコレクションまたはシーケンスの処理は、通常、F# の再帰を使用して行われます。 F# では、ループや命令型プログラミングもサポートされていますが、正確性を保証するのが簡単であるため、再帰が推奨されます。
マイクロソフトのサイトから抜粋2
F# では、末尾呼び出し最適化も完全にサポートされています。これは、再帰呼び出しを最適化して、ループ コンストラクトと同じ速度でできるようにするための方法です。
抜粋1、抜粋2共に、何を言ってるのか?(苦)理解できたのは、6の階乗だけ。
通常、再帰は例えば次のようなカンジでしょ?
みんな大好き、フィボナッチ数列だと、例えばOCamlでは
let rec fib n = match n with
0 -> 0
| 1 -> 1
| n -> fib (n-1) + fib(n-2)
みたいに書きますよね?再帰呼び出ししてる。これがフツーの再帰、です。
一方、末尾再帰とは、再帰呼び出しした際に、その関数以外の関数、ないしは計算を一切使わないやり方です。
上の例だと再帰関数同士を「足し合わせてる」ので、これは末尾再帰じゃない。
一方、フィボナッチ数列は次のようにも書けます。
let fib n =
let rec iter i a b = match i with
0 -> a
| _ -> iter (i - 1) b (a + b) in
iter n 0 1;;
こっちのフィボナッチ数列はローカル関数(局所関数とも言う)iterを定義してますが、そこで再帰してます。
注目して欲しいのは関数iter内でiterを呼び出す際に、iter以外は呼び出してないし、それ以外の事をしてません。
こういうスタイルの再帰を末尾再帰、と言います。
SchemeもRacketもOCamlもF#も、原則、末尾再帰で再帰関数を書いた場合、内部的にはジャンプ構文に変換されます。そして再帰によるスタックの無駄遣いを起こしません。
こういう機能を末尾再帰最適化(TCO: Tail Call Optimization)と呼びます。
Microsoftが言ってるのは、F#で末尾再帰を書けば、それは効率良く.net上、つまり仮想マシン上でジャンプ構文に変換され、C#やVB.netでforループやwhileループを書くのと同じ効率を保証してる、って事です。
つまり「末尾再帰をガンガン使ってくれた方がF#らしいコードになるよ」って言ってるだけ、ですね。
反面、PythonなんかではTCOが実装/保証されてないので、メンド臭い、ってのは何度か指摘してる通りです。