如何在Haskell中有效地重用stdin输入

如何在Haskell中有效地重用stdin输入,haskell,Haskell,我明白我不应该因为有关的错误而尝试重新读取stdin 例如,在下文中: main = do x <- getContents putStrLn $ map id x x <- getContents --problem line putStrLn x 但这会成为性能/内存问题吗?GHC是否必须将从stdin读取的所有内容保留在主存储器中 我想象第一次消费x时,GHC可以扔掉已经处理的x部分。因此,理论上,GHC只能使用少量的常量内存进行处理。但由于我们要一次

我明白我不应该因为有关的错误而尝试重新读取
stdin
例如,在下文中:

main = do
  x <- getContents
  putStrLn $ map id x
  x <- getContents     --problem line
  putStrLn x
但这会成为性能/内存问题吗?GHC是否必须将从
stdin
读取的所有内容保留在主存储器中

我想象第一次消费
x
时,GHC可以扔掉已经处理的
x
部分。因此,理论上,GHC只能使用少量的常量内存进行处理。但由于我们要一次又一次地使用
x
,GHC似乎不能扔掉任何东西。(也不能从
stdin
中再次读取)


我对记忆含义的理解正确吗?如果是这样,是否有修复方法?

是的,您的理解是正确的:如果重用
x
,ghc必须将其全部保存在内存中

我认为一个可能的解决办法是懒惰地(一次)消费它

假设您希望将
x
输出到多个输出句柄
hdl::[Handle]
。天真的做法是:

main :: IO ()
main = do
    x <- getContents
    forM_ hdls $ \hdl -> do
        hPutStr hdl x
这里我们转置了循环:我们不迭代句柄(每个句柄迭代输入字符),而是迭代输入字符,并将每个字符打印到每个句柄


我还没有测试过它,但是这个表单应该可以保证我们不需要太多的内存,因为每个输入字符
c
都使用了一次,然后就被丢弃了。

是的,它必须在内存中保留所有的stdin。我看不出修复是如何可能的:您是否希望您的程序丢弃数据并在以后仍然可以使用它?也许你正在寻找类似于
dox的东西,你完全正确
dox{cs粗略地说,我希望使用Haskell来实现UNIX
tee
命令或它的一个变体。谢谢。我可以看到您的示例是如何工作的。但是我可能需要比这里的同步处理程序更复杂的东西。例如,如果我需要在第二轮中对流进行
反转
排序
,我猜是什么原因重新下线,它将中断。@tinlyx
reverse
sort
将强制累积所有输入,它们是教科书中的非流式操作。
length
或word count等将起作用。感谢您的澄清。您认为如果我在大流上使用例如
reverse
,我会得到相同的mem吗不管怎样,不管它是否在第二轮中使用?是的。只是
do{cs
main = do
  x <- getContents
  putStrLn $ map id x
  putStrLn x
main :: IO ()
main = do
    x <- getContents
    forM_ hdls $ \hdl -> do
        hPutStr hdl x
main :: IO ()
main = do
    x <- getContents
    forM_ x $ \c -> do
        forM_ hdls $ \hdl -> do
            hPutChar hdl c