这是我的代码:(获取文件行号和字数)
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
这也有同样的问题......并且有很多记忆,所以,任何人都可以解决这个问题吗?我只是哈斯克尔的新学习者。
答案 0 :(得分: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