2014-01-20 97 views
3

我剛寫了一段Haskell代碼,爲了調試我的代碼,我在代碼中放入了一堆打印語句(所以,我最重要的函數返回IO t,當它只是需要返回t),我看到這個函數在成功運行時會佔用大量內存(大約1.2GB)。有一次,我看到該程序工作正常,我刪除從功能的所有打印語句和運行它,才知道原來這是給我這個錯誤:Haskell內存使用情況和IO

Stack space overflow: current size 8388608 bytes. 
Use `+RTS -Ksize -RTS' to increase it. 

即使那是完全相同的一塊代碼,由於某些原因,打印語句使其忽略堆棧空間溢出。任何人都可以啓發我爲什麼會發生這種情況?

我知道我沒有提供我的代碼,這可能會使得難以回答這個問題,但我已經把一堆東西一起砍了,它看起來並不漂亮,所以我懷疑它會有用,而我我相當肯定唯一的區別是印刷報表。

編輯:

由於人們真正想看看這裏的代碼的相關部分:

linkCallers :: ([Int], Int, Int, I.IntDisjointSet, IntMap Int) -> ([Int], Int, Int, I.IntDisjointSet, IntMap Int) 
linkCallers ([], x, y, us, im) = ([], x, y, us, im) 
linkCallers ((a:b:r), x, y, us, im) = if a == b 
    then (r, x, y+1, us, im) 
    else if sameRep 
     then (r, x+1, y+1, us, im) 
     else (r, x+1, y+1, us', im') 
     where 
      ar = fst $ I.lookup a us 
      br = fst $ I.lookup b us 
      sameRep = case ar of 
       Nothing -> False 
       _ -> ar == br 
      as' = ar >>= flip lookup im 
      bs' = br >>= flip lookup im 
      totalSize = do 
       asize <- as' 
       bsize <- bs' 
       return $ asize + bsize 
      maxSize = (convertMaybe as') + (convertMaybe bs') 
      us' = I.union a b $ I.insert a $ I.insert b $ us 
      newRep = fromJust $ fst $ I.lookup a us' 
      newRep' = fromJust $ fst $ I.lookup b us' 
      im'' = case ar of 
       Nothing -> case br of 
        Nothing -> im 
        Just bk -> delete bk im 
       Just ak -> delete ak $ case br of 
        Nothing -> im 
        Just bk -> delete bk im 
      im' = case totalSize of 
       Nothing -> insert newRep maxSize im'' 
       Just t -> insert newRep t im'' 

startLinkingAux' (c,x,y,us,im) = let [email protected](_,x',_,us',im') = linkCallers (c,x,y,us,im) in 
    case (fst $ I.lookup primeMinister us') >>= flip lookup im' >>= return . (>=990000) of 
     Just True -> x' 
     _ -> startLinkingAux' t 

startLinkingAux'看慣了這樣的事情:

startLinkingAux' (c,x,y,us,im) = do 
    print (c,x,y,us,im) 
    let [email protected](_,x',_,us',im') = linkCallers (c,x,y,us,im) in 
    case (fst $ I.lookup primeMinister us') >>= flip lookup im' >>= return . (>=990000) of 
     Just True -> return x' 
     _ -> startLinkingAux' t 
+0

您是否在程序完成之前終止了您的程序? –

+2

您應至少在刪除打印的位置顯示一個功能。 – Zeta

+3

只是一個預感:嘗試強迫(評估)您用來打印它們的值,看看它是否有所作爲。 – fjh

回答

1

有可能是一個內存泄漏的一個參數。也許我會嘗試的第一件事是要求作者disjoint-set爲​​添加一個RFData實例(或者自己動手,查看源代碼,它相當容易)。然後嘗試撥打force,查看linkCallers返回的所有值,看看它是否有幫助。

其次,你沒有使用disjoint-set的權利。該算法的主要思想是查找壓縮集合中的路徑。這就是它的好表現!所以每次查找時,都應該用新的替換舊套件。但是這使得在功能語言中使用一個非常笨拙的不相交集。它會建議使用State單子爲此,並在內部使用它在linkCallers,作爲一個大do塊而不是where,只是通過起始集和提取最後一個。並定義如

insertS :: (MonadState IntDisjointSet m) => Int -> m() 
insertS x = modify (insert x) 

lookupS :: (MonadState IntDisjointSet m) => Int -> m (Maybe Int) 
lookupS x = state (lookup x) 

-- etc 

使用裏面State。 (也許他們會到庫的很好的貢獻,以及這很可能是一個普遍的問題。)

最後,還有很多小的改進,可以使代碼更易讀:

很多時候你正在將一個函數應用於兩個值。我建議定義像

onPair :: (a -> b) -> (a, a) -> (b, b) 
onPair f (x, y) = (f x, f y) 
-- and use it like: 
(ar, br) = onPair (fst . flip I.lookup us) (a, b) 

而且使用Applicative功能可以讓事情變得更短的東西:

sameRep = fromMaybe False $ (==) <$> ar <*> br 
totalSize = (+) <$> as' <*> bs' 

然後還

im'' = maybe id delete ar . maybe id delete br $ im 
im' = insert newRep (fromJust maxSize totalSize) im'' 

希望它能幫助。