6

我正在使用管道库,需要String使用 ASCII 编码将 ByteString 流转换为行流(即)。我知道还有其他库(Pipes.Text 和 Pipes.Prelude)可能让我更轻松地从文本文件中生成行,但是由于其他一些代码,我需要能够StringByteString.

更正式地说,我需要将 a 转换Producer ByteString IO ()为 a Producer String IO (),这会产生线条。

我敢肯定,对于经验丰富的 Pipes-Programmer 来说,这一定是单线,但到目前为止,我还没有成功破解 Pipes-ByteString 中的所有FreeTLens-trickery。

任何帮助深表感谢!

斯蒂芬

4

2 回答 2

5

如果您需要该类型签名,那么我建议您这样做:

import Control.Foldl (mconcat, purely)
import Data.ByteString (ByteString)
import Data.Text (unpack)
import Lens.Family (view)
import Pipes (Producer, (>->))
import Pipes.Group (folds)
import qualified Pipes.Prelude as Pipes
import Pipes.Text (lines)
import Pipes.Text.Encoding (utf8)
import Prelude hiding (lines)

getLines
    :: Producer ByteString IO r -> Producer String IO (Producer ByteString IO r)
getLines p = purely folds mconcat (view (utf8 . lines) p) >-> Pipes.map unpack

这是有效的,因为类型purely folds mconcat是:

purely folds mconcat
    :: (Monad m, Monoid t) => FreeT (Producer t m) r -> Producer t m r

...t在这种情况下将是Text

purely folds mconcat
    :: Monad m => FreeT (Producer Text m) r -> Producer Text m r

任何时候你想减少你可能想要使用Producer的 -delimited 流的每个子组。那么这只是选择减少子组的权利的问题。在这种情况下,您只想连接组中的所有块,因此您传入. 我通常不建议这样做,因为它会在非常长的行上中断,但您指定您需要这种行为。FreeTpurely foldsFoldTextmconcat

这很冗长的原因是因为pipes生态系统Text过度推广String并且还试图鼓励处理任意长的行。如果您不受其他代码的限制,那么更惯用的方法就是:

view (utf8 . lines)
于 2015-01-01T00:34:21.850 回答
1

经过一些黑客攻击和这个博客的一些提示,我想出了一个解决方案,但它非常笨拙,而且我担心效率有点低,因为它使用了 ByteString.append:

import Pipes
import qualified Pipes.ByteString as PB
import qualified Pipes.Prelude as PP
import qualified Pipes.Group as PG
import qualified Data.ByteString.Char8 as B
import Lens.Family (view )
import Control.Monad (liftM)

getLines :: Producer PB.ByteString IO r -> Producer String IO r
getLines = PG.concats . PG.maps toStringProducer . view PB.lines

toStringProducer :: Producer PB.ByteString IO r -> Producer String IO r
toStringProducer producer = go producer B.empty
  where
    go producer bs = do
        x <- lift $ next producer
        case x of
            Left r -> do
                yield $ B.unpack bs
                return r
            Right (bs', producer') -> go producer' (B.append bs' bs)
于 2014-09-26T10:27:17.357 回答