【问题标题】:Conduit - Combining multiple Sources/Producers into oneConduit - 将多个来源/生产者合二为一
【发布时间】:2014-04-27 10:04:17
【问题描述】:

我正在使用sourceFile 从文件中读取数据,但我还需要在处理操作中引入随机性。我认为最好的方法是有一个类型的生产者

Producer m (StdGen, ByteString)

其中 StdGen 用于生成随机数。

我打算让生产者执行 sourceFile 的任务,并在每次向下游发送数据时产生一个新的种子。

我的问题是,似乎没有像 zipSink 这样的源组合器用于接收器。通读Conduit Overview,似乎建议您可以在Conduit 中嵌入Source,但我看不到示例中是如何完成的。

谁能提供一个示例,将两个或多个 IO 源融合到一个 Producer/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 值附加到文件末尾。 (别问我为什么)

【问题讨论】:

  • 如果你想要管道中的随机性,请使用 monad random。

标签: haskell conduit


【解决方案1】:

您可以为此使用ZipSource。在您的情况下,它可能看起来像:

sourceStdGens :: Source m StdGen
sourceBytes :: Source m ByteString
sourceBoth :: Source m (StdGen, ByteString)
sourceBoth = getZipSource $ (,)
    <$> ZipSource sourceStdGens
    <*> ZipSource sourceBytes

【讨论】:

  • 或者,如果您只需要压缩 2 个源,Data.Conduit.Internal.zipSources,但 ZipSource 类型通过为输出参数添加 Applicative 实例来概括该功能。
【解决方案2】:

您可以在 IO monad 中执行此操作,然后将结果提升到 Producer。

do (i, newSeed) <- next currentSeed
   b <- generateByteStringFromRandomNumber i
   return (b, newSeed)

这个 IO 动作可以通过一个简单的提升提升到适当的管道中:

-- assuming the above action is named x and takes the current seed as an argument
-- the corresponding producer/source is:
lift $ x currentSeed

【讨论】:

  • 您能否提供一个示例,将 IO 操作“提升”到 Producer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2019-09-30
相关资源
最近更新 更多