하스켈을 배우려고 할 때 함수와 재귀를 올바르게 이해하기 위해 pi 계산을 구현했습니다.숫자를 표시하려고 시도 할 때 GHCI의 스택 오버플로
파이를 계산하는 Leibniz Formula을 사용하여, 나는 주어진 파라미터의 허용 오차에 파이를 인쇄 다음, 함께했다, 그리고 재귀 함수의 수는 그 값을 얻기 위해 호출
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
이것은 완전히 반 직관적 인 것처럼 보입니다. 실제 계산은 정상적으로 작동하지만 재귀 호출이 얼마나 실패했는지 인쇄하려고합니다.
왜 이렇게됩니까?
썽크가 무엇인지 모를 경우 (하스켈을 시작했을 때 나는하지 않았다!) 기본적으로 미해결의 계산이다. 첫 번째 예에서는'count'를 출력하기 전에'2000'의 값을 가지지 않고'... + 1) +1의 값을가집니다 +1) +1) +1) +1)'' (나는 시작에서 2000 개의 왼쪽 괄호를 생략했다 : P). 인쇄 할 때 실제로 추가됩니다. –
@DanielBuckmaster가 중요한 점은 덩어리가 계속해서 더 많은 메모리를 사용하고있는 반면, 하나는 순식간에 '카운트'가 'Int'(우주의 상수) . 당신은 이것에 익숙해 질 것입니다. 그러나 확실히 당신을 물 수있는 것입니다. – gspr