Haskellにおける末尾再帰の最適化

 Haskellにおいて、末尾再帰の最適化というのは、どうなっているのだろう?気になったので、ちょっと試してみた。適当に階乗を定義して、実験してみる。

fact 0 = 1
fact n = n * fact (n - 1)

 末尾再帰にすらなっていないが、このfactは、fact 100000とか実行しても、ちゃんと計算が行われる。スタックは溢れない。(計算に10分ぐらいかかるけど…。)もちろん、末尾再帰の形に書き直してもちゃんと動く。
 Haskell WikiのTail Recursiveの項によると、「Haskellのような遅延評価型の言語においては、末尾再帰で書いたからといって、スタックの使用量が減るとは限らないよーん(もしコンパイラが末尾再帰の最適化を行ったとしてもね)」と書いてある。ここだけ読むと、単なる普通の再帰も賢く最適化するので末尾再帰の方が効率よくなるとは限らないよ、という意味である可能性もなくはないが、後ろに「seqとか使って正格な評価を行ってやらないと、末尾再帰の形でもメモリを馬鹿喰いする可能性があるよ」と続いている。ここでの文の意味は、末尾再帰を最適化したらとりあえずスタックは食わなくなるけど、遅延評価だから別の所でメモリを食うかもよ、という意味にしか取れない。つまり、fact 5 とか実行すると、fact 5 = 5 * fact 4 = 5 * 4 * fact 3 = .... = 5 * 4 * 3 * 2 * 1と、わざわざ長々とした式をメモり上に保持して、最後に計算して120を出力する、という動作をするかもよ、という事だ。(この例は末尾再帰じゃないけど、言いたいことは理解してもらえると思う。)
 とりあえず、言語仕様には入ってないけど、実装によっては末尾再帰の最適化が入っている事もありそうな気がする、という、中途半端な結論。