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

RnM*_*Mss 3 haskell lazy-evaluation

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

main = do
    s <- getText
    putStr s
Run Code Online (Sandbox Code Playgroud)

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

但是,以下代码:

main = do
    s <- getContents
    putStr s
Run Code Online (Sandbox Code Playgroud)

它在输入后立即显示该行.

鉴于功能getChar,我可以写一个getText表现得像getContents

Don*_*art 8

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

getText = unsafeInterleaveIO $ do
    c <- getChar
    s <- getText
    return (c : s)
Run Code Online (Sandbox Code Playgroud)

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


sab*_*uma 7

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

getText = do
    c <- getChar
    s <- unsafeInterleaveIO $ getText
    return (c : s)
Run Code Online (Sandbox Code Playgroud)

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

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

getText = lazyDoIO getChar
Run Code Online (Sandbox Code Playgroud)

然而,大多数Haskellers都会为此感到畏缩.如果你想对IO生成的数据进行增量流处理,那么使用像Pipes或的库会更安全Conduits.