我有5000个矢量,保存在5000个文件中。我需要找到他们的总和。 DF2类型只是Vector Double
的同义词,并且是Num的一个实例。所以我阅读并解析所有这些文件以列出[IO DF2]
并折叠它:
getFinal :: IO DF2
getFinal = foldl1' (liftA2 (+)) $ map getDF2 [1..(sdNumber runParameters)]
where getDF2 i = fmap parseDF2 $ readFile ("DF2/DF2_" ++ show i)
但是我收到错误:
DF2: DF2/DF2_1022: openFile: resource exhausted (Too many open files)
谷歌透露这个问题很常见:
然而,我没有得到懒惰IO的问题。如果它是懒惰的,那为什么它在需要之前打开文件?我不明白如何使Duncan Coutts的elegant solution适应我的情况。
答案 0 :(得分:6)
并不是它在需要之前打开文件;这是因为它不会关闭它们,直到你强制整个字符串。解决这个问题的一个简单方法是在读取后立即强制整个字符串;由于Vectors是严格的,最简单的方法是在解析Vector之后强制对它进行求值:
getFinal :: IO DF2
getFinal = foldl1' (liftA2 (+)) $ map getDF2 [1..(sdNumber runParameters)]
where getDF2 i = readFile ("DF2/DF2_" ++ show i) >>= evaluate . parseDF2
这使用Control.Exception.evaluate;您可以将evaluate
视为强制其参数然后返回它。这只适用于parseDF2
消耗整个字符串的情况。
更优雅的解决方案是完全摆脱懒惰的IO,并使用迭代或类似的东西。但对于这么简单的用例,这可能不值得。