Haskellを学ぶために、関数と再帰を正しく理解するために円周率計算を実装しました。
ライプニッツの公式を使用して円周率を計算すると、次のようになります。円周率は、指定されたパラメーターの許容誤差と、その値を取得するための再帰関数呼び出しの数に出力されます。
reverseSign :: (Fractional a, Ord a) => a -> a
reverseSign num = ((if num > 0
then -1
else 1) * (abs(num) + 2))
piCalc :: (Fractional a, Integral b, Ord a) => a -> (a, b)
piCalc tolerance = piCalc' 1 0.0 tolerance 0
piCalc' :: (Ord a, Fractional a, Integral b) => a -> a -> a -> b -> (a, b)
piCalc' denom prevPi tolerance count = if abs(newPi - prevPi) < tolerance
then (newPi, count)
else piCalc' (reverseSign denom) newPi tolerance (count + 1)
where newPi = prevPi + (4 / denom)
したがって、これをGHCIで実行すると、期待どおりに機能するようです。
*Main> piCalc 0.001
(3.1420924036835256,2000)
しかし、許容値を細かく設定しすぎると、次のようになります。
*Main> piCalc 0.0000001
(3.1415927035898146,*** Exception: stack overflow
これは私には完全に直感に反しているようです。実際の計算は正常に機能しますが、再帰呼び出しの数を出力しようとすると失敗しますか?
なんでそうなの?