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

时间:2017-02-11 20:55:50

标签: haskell

我知道由于Haskell IO - handle closed的错误,我不应该尝试重新阅读"{"filterBy"=>"name", "controller"=>"resource_name", "action"=>"index", "sortBy"=>"name"}" 例如,在下面:

stdin

第二个电话main = do x <- getContents putStrLn $ map id x x <- getContents --problem line putStrLn x 将导致错误:

x <- getContents

当然,我可以省略从test: <stdin>: hGetContents: illegal operation (handle is closed) 读取的第二行。

getContents

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

我想第一次消耗stdin时,GHC可以丢弃已经处理过的x部分。因此从理论上讲,GHC只能使用少量的常量内存进行处理。但是,由于我们将再次使用x(并且再次),似乎GHC不能扔掉任何东西。 (也不能再从x读取。)

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

1 个答案:

答案 0 :(得分:2)

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

我认为可能的解决方法是懒散地消耗它(一次)。

假设您要将x输出到多个输出句柄hdls :: [Handle]。天真的方法是:

main :: IO ()
main = do
    x <- getContents
    forM_ hdls $ \hdl -> do
        hPutStr hdl x

这会将stdin读入x,因为第一个hPutStr遍历字符串(至少对于无缓冲的句柄,hPutStr只是一个调用hPutChar的循环}对于字符串中的每个字符)。从那时起,它将被保存在所有后续hdl的内存中。

可替换地:

main :: IO ()
main = do
    x <- getContents
    forM_ x $ \c -> do
        forM_ hdls $ \hdl -> do
            hPutChar hdl c

这里我们转换了循环:不是迭代句柄(并且每个句柄迭代输入字符),我们迭代输入字符,对于每个字符,我们将它打印到每个句柄。

我还没有对它进行过测试,但是这种形式应该保证我们不需要大量的内存,因为每个输入字符c只使用一次然后丢弃。