【问题标题】:using haskell pipes-bytestring to iterate a file by line使用haskell管道字节串逐行迭代文件
【发布时间】:2014-11-16 21:34:54
【问题描述】:

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

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

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

非常感谢任何帮助!

斯蒂芬

【问题讨论】:

  • lined :: Monad m => Producer ByteString m r -> Producer String m (Producer ByteString m r)lined = folds mappend mempty T.unpack . view PT.lines . PTE.decodeAscii。如果要删除可能的不可读字节串剩余,请添加Control.Monad.void

标签: haskell-pipes


【解决方案1】:

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

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

任何时候你想减少FreeT-delimited流的每个Producer子组,你可能想使用purely folds。然后只需选择正确的Fold 来减少子组。在这种情况下,您只想连接组内的所有Text 块,因此您传入mconcat。我通常不建议这样做,因为它会在非常长的行上中断,但您指定您需要这种行为。

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

view (utf8 . lines)

【讨论】:

  • 很好的答案,谢谢!也有助于理解这个库中的镜头。
【解决方案2】:

经过一些黑客攻击和来自blog 的一些提示后,我想出了一个解决方案,但它非常笨拙,而且我担心效率也有点低,因为它使用了 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-25
    • 2021-08-27
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多