我创建了一系列流程“步骤”,这些步骤的实现方式使尽早输出信息成为可能。
例如
mainFromSettings :: Settings -> IO ()
...
mainFromSettings ... =
do
Sys.setInputEcho False
Sys.hSetBuffering Sys.stdout Sys.NoBuffering
sContent <- getContents
let
records :: [[String]]
records = Rcr.fromContent rcrConfig sContent
...
print records
字符串
上面的代码片段在每次从延迟IO流'sContent'构建记录时打印一条记录。
我想这是因为一旦输入了一行,“打印记录”就占据了准备打印的列表的头部。我还假设当列表的顺序颠倒时,这将不起作用。
不幸的是,在其中一个处理步骤中,它不是这样工作的。对于这个处理步骤,记录列表必须在单个字符显示之前完成。这个函数的区别是一个额外的IO函数,为每个记录提供额外的信息。
为了理解这个问题,我创建了下面的代码来模拟这个额外的IO函数。该代码还模拟了已经可用的记录(以避免打开句柄的冲突)。
import qualified System.IO as Sys
import qualified System.IO.Echo as Sys
main :: IO ()
main =
Sys.setInputEcho False >>
Sys.hSetBuffering Sys.stdout Sys.NoBuffering >>
Sys.hSetBuffering Sys.stdin Sys.NoBuffering >>
checkAll ["12","34","56"] >>=
print
checkAll :: [String] -> IO [String]
checkAll [] = return []
checkAll (s:lrs) =
do
l <- getLine
let
symbol = if l == s then "==" else "/="
p1 = l ++ symbol ++ s
p2 <- checkAll lrs
return (p1 : p2)
型
上面的代码只有在所有三行都完成时才完成。
我也尝试了一个'foldrM'的替代品,但它没有工作,实际上:
import qualified System.IO as Sys
import qualified System.IO.Echo as Sys
import qualified Data.Foldable as Fld
main :: IO ()
main =
Sys.setInputEcho False >>
Sys.hSetBuffering Sys.stdout Sys.NoBuffering >>
Sys.hSetBuffering Sys.stdin Sys.NoBuffering >>
checkAll [] ["12","34","56"] >>=
print
checkAll :: [String] -> [String] -> IO [String]
checkAll = Fld.foldrM f
where
f :: String -> [String] -> IO [String]
f s ls =
do
l <- getLine
if l == s
then return (ls ++ [l ++ "==" ++ s])
else return (ls ++ [l ++ "/=" ++ s])
型
也就是说,只有当所有三条线都完成时,它才完成。
只要我删除中间的IO函数,就像这样:
import qualified System.IO as Sys
import qualified System.IO.Echo as Sys
main :: IO ()
main =
Sys.setInputEcho False >>
Sys.hSetBuffering Sys.stdout Sys.NoBuffering >>
Sys.hSetBuffering Sys.stdin Sys.NoBuffering >>
getContents >>=
print . lines
型
.它像预期的那样工作,即使函数行介于两者之间。
那么,我该怎么做才能实现这种行为呢?使用这种懒惰IO方法是否可能实现?我是否需要管道来实现这一点?
已经审议了以下专题:
Haskell - Read Lines from Handle without blocking
1条答案
按热度按时间iovurdzv1#
checkAll
确实 * 字面上 * 对do
getLine
说,然后在 *return
ing任何数据之前递归地做checkAll
*。“懒惰”IO不是懒惰求值的自然结果(正常代码免费获得)。这是unsafeInterleaveIO
引入的一种神奇的行为。对这个函数的调用隐藏在getContents
这样的库函数中。您可以通过自己调用
unsafeInterleaveIO
来使checkAll
参与惰性IO。字符串
我强烈建议使用适当的流库而不是懒惰IO。懒惰IO是一个巧妙的技巧,可以使真正简单的程序比它们“应该”的响应速度更快,但永远不应该被依赖。在这方面,我会指出,你建议的
conduit
包真的是矫枉过正。你不需要比streaming
的Stream
更多的东西,也就是免费的monad TransformerFreeT
。