2012-04-01 12 views
0
ここ

は私のコードです: スタックスペースのオーバーフロー:haskellでスタックオーバーフローエラーなしで大きなファイルを処理する方法は?

import System.IO 
import Data.Maybe 
readL::(Int,Int,Int)->IO() 
readL (w,l,-1) = do 
       putStrLn $ "word:" ++(show w)++"\nline:"++(show l) 
readL (w,l,0) = do 
       s<-hIsEOF stdin 
       if s 
         then readL (w,l,-1) 
         else 
           do 
           f<-getLine 
           readL (w+length f,l+1,0) 

main = do 
     hSetBinaryMode stdin True 
     readL (0,0,0) 

私はサイズの100メートルでファイルを処理し、それだけでエラーが発生し、クラッシュ(ファイルの行のnumと単語数を取得)現在のサイズ8388608バイト

私が間違って書いたことはありますか?私はHaskellの中にちょうど新しい学習者よ、誰もがこれをsloveすることができ、

import System.IO 
import Data.List 
main = do 
     hSetBinaryMode stdin True 
     interact $ (\(w,l)->"line:"++(show l)++"\nwords:"++(show w)++"\n"). foldl' (\(w,l) r-> (w + length r,l+1)) (0,0) .lines 

これも同じ問題を抱えている...と、多くのメモリと、そう?

は、私もここで別のバージョンがあります。

答えて

2

readLへのwlも、入力が終わる前に評価されないという問題があります。したがって、多くの行を含む入力の場合、lと同様の巨大なサンク(((0 + length line1) + length line2) ... + length lastline)を作成し、50万行以上を超えるサンクは利用可能なスタックに収まらないと評価します。さらに、length fは、評価されるまでラインの読み取りを保持し、不必要に大きなメモリ使用を引き起こします。あなたがループ内で評価され蓄積したパラメータを維持する必要があり

は、最も簡単な方法は、バングパターン

readL !(!w,!l,-1) = ... 

またはseqである:

readL (w,l,c) 
    | w `seq` l `seq` (c == -1) = putStrLn $ "word:" ++(show w)++"\nline:"++(show l) 
readL (w,l,0) = do 
       s<-hIsEOF stdin 
       if s 
         then readL (w,l,-1) 
         else 
           do 
           f<-getLine 
           readL (w+length f,l+1,0) 

foldl'バージョンは同じ問題を抱えています、

foldl' (\(w,l) r-> (w + length r,l+1)) (0,0) 

は、アトアペアから弱いヘッドノーマルフォームへの変換、つまり最も外側のコンストラクタへの、ここでは(,)です。コンポーネントの評価は強制されません。これを行うには、あなたは

  • 私はそれを作っ倍

    data P = P !Int !Int 
    
    foo = ... . foldl' (\(P w l) r -> P (w + length r) (l+1)) (P 0 0) . lines 
    
  • または折りたたまれた機能

    ... . foldl' (\(w,l) r -> w `seq` l `seq` (w + length r, l+1)) . lines 
    
+0

seqを使用するための厳格なペアタイプを使用することができ、感謝とても大変です! – vzex

+0

なぜ 'foldl 'が役に立たないのかという言葉をいくつか追加しました。 –

+0

最後の質問は、ループバージョンよりもfoldl 'バージョンの方が遅いですか?つまり、foldlのバージョンはすべての行をメモリに分割して処理します。あるいは、lazyの機能のために、linuxのパイプのように、ループバージョンのように動作しますか? – vzex

関連する問題