3
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行为像getContents吗?

4

3 回答 3

8

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

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

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

于 2013-02-16T15:52:30.543 回答
7

这可以通过unsafeInterleaveIO函数 from 来完成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 会在这样做时畏缩。如果您想对生成的数据进行增量流处理,使用类似orIO的库会更安全。PipesConduits

于 2013-02-16T15:51:56.077 回答
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
于 2013-02-16T16:03:13.857 回答