我们得到sourceFile
一个 ByteString 流。
参考我的另一个问题“将多个源/生产者组合成一个”,我能够使用 获取 (StdGen, ByteString)的源ZipSink
,sourceFile
以及生成无限 StdGen 流的自定义源。
我想要实现的是将每个 StdGen 与一个字节的 ByteString 配对,但是在我当前的实现中,我得到一个 StdGen 与来自sourceFile
.
我已经研究了Conduit.Binary
's 的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
,产生head
传入的 ByteString 流,leftOver
其余的(将它放回传入流的队列)。基本上,我要做的是将传入的 ByteString 流切成字节块。
我是否正确使用它?如果isolate
不是我应该使用的功能,那么任何人都可以提供另一个将其拆分为任意字节块的功能吗?