【发布时间】:2014-06-15 07:26:27
【问题描述】:
使用sourceFile,我们得到一个字节串流。
参考我的另一个问题"Combining multiple Sources/Producers into one",我可以使用ZipSink、sourceFile 和一个生成无限StdGen 流的自定义源来获取(StdGen,ByteString)的来源。
我想要实现的是将每个 StdGen 与一个字节的 ByteString 配对,但在我当前的实现中,我得到一个 StdGen 与来自sourceFile 的输入文件的全部内容配对。
我已经查看了Conduit.Binary 的isolate 函数,但是当我按如下方式使用时它似乎对我不起作用:
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
import System.Random (StdGen(..), split, newStdGen, randomR)
import ClassyPrelude.Conduit as Prelude
import Control.Monad.Trans.Resource (runResourceT, ResourceT(..))
import qualified Data.ByteString as BS
import Data.Conduit.Binary (isolate)
-- generate a infinite source of random number seeds
sourceStdGen :: MonadIO m => Source m StdGen
sourceStdGen = do
g <- liftIO newStdGen
loop g
where loop gin = do
let g' = fst (split gin)
yield gin
loop g'
-- combine the sources into one
sourceInput :: (MonadResource m, MonadIO m) => FilePath -> Source m (StdGen, ByteString)
sourceInput fp = getZipSource $ (,)
<$> ZipSource sourceStdGen
<*> ZipSource (sourceFile fp $= isolate 1)
-- a simple conduit, which generates a random number from provide StdGen
-- and append the byte value to the provided ByteString
simpleConduit :: Conduit (StdGen, ByteString) (ResourceT IO) ByteString
simpleConduit = mapC process
process :: (StdGen, ByteString) -> ByteString
process (g, bs) =
let rnd = fst $ randomR (40,50) g
in bs ++ pack [rnd]
main :: IO ()
main = do
runResourceT $ sourceInput "test.txt" $$ simpleConduit =$ sinkFile "output.txt"
在 Conduit 方面,我认为 isolate 将执行 await,产生传入 ByteString 流的 head,并产生 leftOver 其余部分(将其放回传入流的队列)。基本上,我要做的是将传入的 ByteString 流切成字节块。
我是否正确使用它?如果isolate 不是我应该使用的函数,那么任何人都可以提供另一个将其拆分为任意字节块的函数吗?
【问题讨论】:
-
让我看看我是否理解正确。你是说你想要一个单独的
StdGen每个Word8?换句话说,您想要(StdGen, Word8)的流? -
@Michael,没错。
-
@MichaelSnoyman,你能检查一下我写的管道吗? (
condWord)。我是否只是重新发明了轮子,因为我希望Conduit.Binary库有类似的东西(并且可能更通用)