2

我想将一个巨大的列表 A 保存到一个文本文件中。writeFile 似乎只在 A 计算的最后保存列表,因为我的内存不足以存储整个列表而崩溃。

我已经尝试过使用

writeFile "test.txt" $ show mylistA

现在我尝试保存列表的元素,因为它们是使用以下方法计算的:

[appendFile "test2.txt" (show x)|x<-mylistA]

但它不起作用,因为:

使用 `print' 导致 (Show (IO ())) 没有实例可能的修复:在交互式 GHCi 命令的 stmt 中添加 (Show (IO ())) 的实例声明:打印它

你能帮我解决这个问题,或者给我一个将我的巨大列表 A 保存到文本文件的解决方案吗?

谢谢

4

3 回答 3

4

问题是您的列表具有类型[ IO () ]或“IO 操作列表”。由于它IO位于 out 类型的“内部”,我们无法在 IO monad 中执行它。我们想要的是IO (). 所以列表理解不会在这里破解它。

我们可以使用函数来转[IO ()] -> IO [()],但这种情况适合于更简洁的组合器。

相反,我们可以使用一个简单的预定义组合器,称为mapM_. 在 Haskell prelude 中,M它是一元的,在我们的例子_中是返回的。在这种情况下使用它是微不足道的m ()IO ()

[appendFile "test2.txt" (show x)|x<-mylistA]

变成

mapM_ (\x -> appendFile "test2.txt" (show x)) myListA

mapM_ (appendFile "test2.txt" . show) myListA

这将展开为

appendFile "test2.txt" (show firstItem) >>
appendFile "test2.txt" (show secondItem) >>
...

所以我们永远不会在内存中拥有整个列表。

于 2013-08-01T10:26:38.890 回答
2

您可以使用函数sequencefromControl.Monad获取(延迟生成的)IO 操作列表并一次执行一个

>>> import Control.Monad

现在你可以做

>>> let myList = [1, 2, 3]
>>> sequence [print x | x <- myList]
1
2
3
[(),(),()]

请注意,您会在最后获得所有返回值的列表。如果要丢弃返回值,只需使用sequence_而不是sequence.

>>> sequence_ [print x | x <- myList]
1
2
3
于 2013-08-01T10:34:42.873 回答
0

forM_我只是想通过提及. 的翻转版本来扩展 jozefg 的答案mapM_。使用forM_你会得到看起来像 foreach 循环的东西:

-- Read this as "for each `x` in `myListA`, do X"
forM_ myListA $ \x -> do
    appendFile "test2.txt" (show x)
于 2013-08-01T13:46:25.940 回答