【问题标题】:Haskell: save one listitem at a time to fileHaskell:一次保存一个列表项到文件
【发布时间】:2013-08-02 05:09:51
【问题描述】:

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

我已经尝试过使用

writeFile "test.txt" $ show mylistA

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

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

但它不起作用,因为:

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

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

谢谢

【问题讨论】:

  • 首先应该没有问题。我使用main = writeFile "test.txt" $ show [x | x &lt;- [1..10^9]] 进行了测试,即使没有优化,它也可以在恒定空间(使用 1.4MB)中运行。也许这是你如何构建mylistA 的东西,它可以防止它被懒惰地消耗(第一个元素是否依赖于后面的元素?)。在这种情况下,您的替代解决方案根本没有帮助,您应该向我们提供更多代码来确定问题的原因。
  • 是的,你是对的,@jozefg 解决方案工作正常,但我的内存使用似乎是由 mylistA 的生成引起的。 myListA 基本上是link @ephemient 的解决方案,我在其中添加了一些额外的约束,例如myListA = [x|x&lt;-(takeWhile (&lt;=10000000000) primes),... ]
  • 也许可以转换成在恒定空间运行。也许不吧。你可以问一个单独的问题。

标签: haskell


【解决方案1】:

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

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

相反,我们可以使用一个简单的预定义组合子 mapM_。在 Haskell 前奏中,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) >>
...

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

【讨论】:

    【解决方案2】:

    您可以使用Control.Monad 中的函数sequence 获取(延迟生成的)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
    

    【讨论】:

      【解决方案3】:

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

      -- Read this as "for each `x` in `myListA`, do X"
      forM_ myListA $ \x -> do
          appendFile "test2.txt" (show x)
      

      【讨论】:

        猜你喜欢
        • 2022-01-22
        • 1970-01-01
        • 2013-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-08
        • 1970-01-01
        • 2016-02-15
        相关资源
        最近更新 更多