저는 Real World Haskell (제 4 장에 있음)을 통해 자신의 길을 만들고 약간의 오프 북을 연습합니다. 다음 프로그램을 만들어 n 번째 소수를 계산했습니다.소수를 계산할 때 스택 공간 오버플로
import System.Environment
isPrime primes test = loop primes test
where
loop (p:primes) test
| test `mod` p == 0 = False
| p * p > test = True
| otherwise = loop primes test
primes = [2, 3] ++ loop [2, 3] 5
where
loop primes test
| isPrime primes test = test:(loop primes' test')
| otherwise = test' `seq` (loop primes test')
where
test' = test + 2
primes' = primes ++ [test]
main :: IO()
main = do
args <- getArgs
print(last (take (read (head args) :: Int) primes))
분명히 소수점 목록을 저장하고 있기 때문에 이것은 지속적인 공간 솔루션이 아닙니다. 문제는 내가 얻을 때 매우 큰 소수가 나는 오류가 나타납니다 ./primes 1000000
말할 수 있습니다 :
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase
내가 꼬리 재귀 권리를 가지고 있음을 상당히 확신을; http://www.haskell.org/haskellwiki/Stack_overflow을 읽고 여기서 여러 가지 응답은 내가 그것이 게으른 평가의 부산물이라고 믿게합니다. 그리고 썽크는 그것이 넘칠 때까지 축적되고 있지만, 지금까지 나는 그것을 고치지 못했습니다. 많은 장소에서 seq
을 사용하여 평가를 시도했지만 효과가 없습니다. 나는 올바른 길을 가고 있는가? 내가 얻지 못하는 다른 것이 있습니까?
당신은 게으름이 꼬리 재귀와 잘 섞이지 않는다는 것이 맞습니다. 그러나 목록으로 작업 할 때 솔루션은 일반적으로 꼬리 - 재귀를 제거하고 게으름을 제거하지 않는 것입니다. – sepp2k
@ sepp2k 일반적으로 TR을 철저하게 제거하지 않고 "tail recursion modulo cons"(단지 * list * cons, * any * cons가 아닌), 일명 가드 재귀로 변환합니다. 그러나 TRMC가 전혀 TR이 아니라고 말하면, IMO를 올바르게 느끼지 못합니다. 어쩌면 그 개념이 그다지 알려지지 않았을 수도 있습니다. :) 그리고 경비가 TRMC가 TRMC가 아니라면, 정확히 말하면 썽크가 쌓이게됩니다. TRMC는 * 상수 * 재귀 호출 간의 작업량을 의미하며, 일반적인 재귀 방식과 마찬가지로 * 호출 전 * 재 호출 전에 재구성됩니다. –