haskell中的懒惰IO:如何返回由某些阻塞的IO生成的惰性列表?

时间:2013-02-16 15:40:42

标签: haskell lazy-evaluation

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

main = do
    s <- getText
    putStr s

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

但是,以下代码:

main = do
    s <- getContents
    putStr s

输入后立即显示该行。

鉴于函数getChar,我可以写一个行为类似于getText的{​​{1}}吗?

3 个答案:

答案 0 :(得分:8)

这是... unsafeInterleaveIO的工作 - 使懒惰IO成为可能的特殊操作。它允许您将IO操作转换为绑定到thunk的操作。然后可以将其存储在结构中,并且该操作仅评估何时需要其结果。

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

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

答案 1 :(得分:7)

这可以通过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
然而,大多数Haskellers都会为此感到畏缩。如果你想做 IO生成的数据的增量流处理,会更安全 使用PipesConduits等库。

答案 2 :(得分: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