【问题标题】:Lazy IO in haskell: How to return a lazy list that is generated by some blocked IO?haskell 中的惰性 IO:如何返回由某些阻塞 IO 生成的惰性列表?
【发布时间】:2013-02-01 10:47:24
【问题描述】:
getText = do
    c <- getChar
    s <- getText
    return (c : s)

main = do
    s <- getText
    putStr s

我希望看到的是每次按“Enter”后都会回显输入行。 但是没有任何回应......(我知道这是一个无限循环) 在执行完上面的所有“IO”之前,它似乎不会“return”。 ...

但是,下面的代码:

main = do
    s <- getContents
    putStr s

输入后立即显示该行。

给定函数getChar,我可以写一个行为类似于getContentsgetText吗?

【问题讨论】:

标签: haskell lazy-evaluation


【解决方案1】:

你谈论 Enter 但你没有在你的代码中检查它。

试试这个:

getText = do
    c <- getChar
    if (c == '\n')
       then return [c]
       else do
              s <- getText
              return (c : s)

main = do
    s <- getText
    putStr s

【讨论】:

  • 它不需要手动检查:在大多数控制台中,您输入的行在生效之前存储在行缓冲区中(以便您可以使用退格或其他东西来修改它),直到您按“Enter”。
  • 但是如果你放置一个无限循环来获取 s 值,你不能假装 {putStr s} 被评估
  • 我已经看到了 unsafeInterleaveIO 效果(在 Don Stewart 提案中),但随后程序并没有终止!
  • 直到你用 Ctrl-z 关闭标准输入
  • 在 {putStr s} 之后添加一个额外的 {putStrLn "Done"} 永远不会被打印
【解决方案2】:

这是为 ... unsafeInterleaveIO 做的工作 - 使惰性 IO 成为可能的特殊操作。它使您可以将 IO 操作转换为绑定到 thunk 的操作。然后可以将其存储在一个结构中,并且该操作只会在需要其结果时进行评估。

getText = unsafeInterleaveIO $ do
    c <- getChar
    s <- getText
    return (c : s)

现在您的getText 立即返回,每个getChar 只暂停计算。如果您需要结果,则运行它。

【讨论】:

    【解决方案3】:

    这可以通过unsafeInterleaveIO 函数来完成 System.IO.Unsafe。然后你的getText 函数就变成了

    getText = do
        c <- getChar
        s <- unsafeInterleaveIO $ getText
        return (c : s)
    

    稍微抽象一下,我们可以得到一个函数来概括这种行为

    lazyDoIO :: IO a -> IO [a]
    lazyDoIO act = unsafeInterleaveIO $ do
        now <- act
        rest <- lazyDoIO act
        return (now : rest)
    
    getText = lazyDoIO getChar
    

    然而,大多数 Haskeller 会在这样做时畏缩。如果你想做 IO生成数据的增量流处理,会更安全 使用像 PipesConduits 这样的库。

    【讨论】:

    • 我正在使用它将一些 API 打包成一些更实用的方法......(因为我不太喜欢 Reactive......)
    • @DonStewart 你的评论是什么意思?在某些情况下,您会推荐惰性 IO o(ve)r 迭代/管道吗?我会说,仅仅因为某些东西(惰性 IO)已经使用了很多年并不意味着它是解决问题的好方法......
    • 我认为你不应该对惰性 IO 感到“畏缩”——它仍然是惯用的 Haskell,组合自然,对于全面的 Haskell 技能必不可少。
    • 只要你做的I/O类型简单(这是一个努力的目标),它就可以自然地组合起来。但如果事情变得复杂,例如更新文件而不是从一个文件读取并写入另一个文件,“自然”的组合将是可怕的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2018-04-17
    • 2016-04-26
    • 2011-07-19
    相关资源
    最近更新 更多