다음의 간단한 하스켈 프로그램은 파일의 항목 목록을 세는 것을 목적으로합니다. foldl'
을 사용하는 버전은 정상적으로 작동하지만 ST Monad
을 사용하는 버전은 스택 공간 오버플로 메시지를 제공합니다. 분명히 여기에 어떤 종류의 공간 누출이 있지만, 나는 그것을 해결할 수 없었습니다. 매우 흥미로운 부분은 ST monad
이 현재 위치에서 업데이트를 수행하고 있어야하며 리소스가 이처럼 커지지 않도록해야한다는 것입니다.하지만 주 메모리와 스택 공간에만 관련 될 수 있습니다. 누군가 여기서 무슨 일이 일어 났는지 설명 할 수 있을까요?ST 모나드의 스택 공간 오버 플로우
import Control.Monad
import Data.List
import Control.Monad.ST
import Data.STRef
--count items using foldl'
countFold :: Num a => [b] -> a
countFold = foldl' (\a _ -> a+1) 0
-- count items using the ST monad
-- derived fromt the sumST example on http://www.haskell.org/haskellwiki/Monad/ST
-- only using +1 instead of adding the values
countST :: Num a => [b] -> a
countST xs = runST $ do
n <- newSTRef 0
forM_ xs (\_ -> modifySTRef n (+1))
readSTRef n
main = do
mydata <- readFile "data_files/values_1000000.num"
let trainingdata = lines mydata
-- this works just fine
--(putStrLn (show (countFold trainingdata)))
-- This fails with the message:
-- Stack space overflow: current size 8388608 bytes.
-- Use `+RTS -Ksize -RTS' to increase it.
(putStrLn (show (countST trainingdata)))
UPDATE : 답변 및 의견 감사합니다. 나는 여기서 무슨 일이 일어 났는지 생각해. modifySTRef '는 버전 4.6에서 새로 추가 된 기능으로 문제를 능숙하게 해결하고 누군가 언급 한 설명을 포함합니다. 나는 우분투에서 표준으로 보이는 Data.STRef 버전 4.5를 사용하고 있으며 설명이나 modifySTRef가 포함되어 있지 않습니다. '
4.6 패키지 버전 함수를 찾고, 그 차이는 ('및 X에 저장된)는 함수 f 엄격히 적용 보장하는 서열을 사용하는 것이다 :
modifySTRef :: STRef s a -> (a -> a) -> ST s()
modifySTRef ref f = writeSTRef ref . f =<< readSTRef ref
modifySTRef' :: STRef s a -> (a -> a) -> ST s()
modifySTRef' ref f = do
x <- readSTRef ref
let x' = f x
x' `seq` writeSTRef ref x'
그래서 다른 방법으로 해결 내 자신의 프로그램 공간에서 함수의 코드를 새로운 이름으로 복사하고 누설 영역에 seq를 적용하는 것이 었습니다. 이것은 앞으로 사용하게 될 훌륭한 범용 트릭입니다. 이 문제를 해결할 수 있도록 도와 주신 모든 분들께 감사드립니다.
[docs] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-STRef.html)를 읽어야합니다. "modifySTRef가 적용되지 않는다는 경고를 받으십시오. 이것은 프로그램이'modifySTRef'를 여러 번 호출하지만 그 값을 거의 사용하지 않는다면 썽크가 메모리에 쌓여 공간 누출이 발생한다는 것을 의미합니다. 이것은 'STREF'를 카운터로 사용할 때 흔히 저지르는 실수입니다. " 실수를 설명하기 위해'countST' 함수의 코드를 거의 닮은 예제도 있습니다. 짧은 이야기 :'modifySTRef '사용 –