通过适当的获取和释放来流式传输资源

时间:2018-06-07 07:27:05

标签: haskell streaming

这是关于Haskell streaming库的问题。

Stream (Of a) m r是“从某些monad m中的操作派生的单个Haskell值的流,并返回类型r的值”。 Streaming.Prelude定义了许多有用的函数,允许很好的流应用程序:

import qualified Streaming.Prelude as S
S.print $ do
    S.yield "a"
    S.yield "b"
    S.yield "c"

tutorial适合入门。

现在,手头的特定问题是如何将此框架与需要仔细实例化和释放资源的monad一起使用。 streaming-with包似乎是正确的候选者,它有一个函数

bracket :: MonadMask m => m a -> (a -> m c) -> (a -> m b) -> m b

获取(m a),发布(a->m c)并使用(a->m b)资源。所有三个操作都封装在返回的m b中。 withFile是如何使用它的一个很好的例子:

withFile :: FilePath -> IOMode -> (Handle -> m r) -> m r
withFile fp md = bracket (liftIO (openFile fp md)) (liftIO . hClose)

获取和释放句柄很好地将用法Handle->m r夹在中间。

但是:我绝对不知道这应该如何与Stream (Of a) m r一起使用。我必须提供a->m b并获得m b。这应该如何连接,以便我获得Stream

要解决这个问题,让我们一起玩withFile

import System.IO 

use :: Handle -> IO (S.Stream (Of String) IO ())
use = return . S.repeatM . hGetLine

main :: IO ()
main = do
    str <- S.withFile "input.dat" ReadMode use
    S.print str

但结果为hGetLine: illegal operation (handle is closed)。这实际上是有道理的,到S.print str被称为withFile时已经获得并释放了句柄。 那么让我们在use函数中移动流消耗:

use :: Handle -> IO ()
use h = do
    S.print $ S.repeatM (hGetLine h)

并且提供hGetLine: invalid argument (invalid byte sequence)。我不太清楚这个错误意味着什么。 isEOFError是可以接受的,但'无效字节序列'?无论如何,这也不起作用。

我的想法已经用完......这是怎么做到的?

withFile只是一个玩具示例,问题实际上是关于如何在bracket内正确创建和使用流。

1 个答案:

答案 0 :(得分:0)

  

让我们在使用功能中移动流消耗

这确实是正确的方法。

我在运行示例代码时实际上得到了正确的hGetLine: end of file。问题是S.repeatM (hGetLine h)从来不会检查它是否已到达文件的末尾,并在碰到它时抛出异常。

use的以下定义没有出现这个问题:

use :: Handle -> IO ()
use h = do
    S.print $ S.untilRight $ do eof <- System.IO.hIsEOF h
                                if eof then Right <$> pure ()
                                       else Left <$> hGetLine h

它使用untilRight函数。