2012-04-01 3 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 м, она просто падает с ошибкой: Стек переполнения пространства: текущий размер 8388608 байт

Есть ли что-то, что я написал неправильно?

У меня также есть другой вариант здесь:

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 

это та же проблема тоже ... и с большим количеством памяти, так что, кто-нибудь может SLOVE это я просто новый ученик в Haskell?.

ответ

2

Проблема в том, что ни один параметр w или l до readL не был оценен до достижения конца ввода. Итак, для ввода со многими строками вы создаете огромные трюки (((0 + length line1) + length line2) ... + length lastline), похожие на l, и для более полумиллиона строк или около того, оценивая, что thunk не поместится в доступный стек. Кроме того, 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 
    
  • или использовать seq в сложенном функции

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

Я сделал это, спасибо u очень много! – vzex

+0

Я добавил несколько слов о том, почему 'foldl'' не помогает. –

+0

Заключительный вопрос, версия foldl 'медленнее, чем версия цикла? Я имею в виду, что версия foldl будет разделять все строки на память, а затем обрабатывать ее, или, из-за ленивой функции, как и в linux, она будет действовать как версия цикла? – vzex

Смежные вопросы