を使用してファイルから読み取っていますsourceFile
が、処理操作にランダム性を導入する必要もあります。私が信じている最善のアプローチは、次のタイプのプロデューサーを持つことです
Producer m (StdGen, ByteString)
ここで、StdGen を使用して乱数を生成します。
プロデューサーが sourceFile のタスクを実行するだけでなく、データをダウンストリームに送信するたびに生成する新しいシードを生成することを意図しています。
zipSink
私の問題は、シンクのようなソースコンバイナーがないように見えることです。Conduit Overviewを読むと、 a を a のSource
中に埋め込むことができることが示唆されているようですがConduit
、例ではそれがどのように行われているかわかりません。
Producer
2 つ以上の IO ソースを 1 つの/に融合する例を誰か提供できますSource
か?
編集 :
例:
{-# 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
-- 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)
-- 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"
したがって、この例では、入力ファイルの内容を取得して出力ファイルに書き込み、ファイルの末尾に 40 ~ 50 のランダムな ASCII 値を追加します。(理由は聞かないで)