使用组合器将管道重新分成更大的块

2024-01-06

我正在尝试构建一个Conduit接收作为输入ByteStrings(每个块大小约为 1kb)并作为输出连接生成ByteString512kb 块。

这看起来应该很简单,但是我遇到了很多麻烦,我尝试使用的大多数策略都只能成功地将块分成更小的块,我还没有成功地连接更大的块。

我开始尝试isolate, then takeExactlyE最终conduitVector,但无济于事。最终我决定这样做:

import qualified Data.Conduit               as C
import qualified Data.Conduit.Combinators   as C
import qualified Data.ByteString            as B
import qualified Data.ByteString.Lazy       as BL

chunksOfAtLeast :: Monad m => Int -> C.Conduit B.ByteString m BL.ByteString
chunksOfAtLeast chunkSize = loop BL.empty chunkSize
  where 
    loop buffer n = do
      mchunk <- C.await
      case mchunk of 
        Nothing -> 
          -- Yield last remaining bytes
          when (n < chunkSize) (C.yield buffer)
        Just chunk -> do
          -- Yield when the buffer has been filled and start over
          let buffer' = buffer <> BL.fromStrict chunk
              l       = B.length chunk
          if n <= l
          then C.yield buffer' >> loop BL.empty chunkSize
          else loop buffer' (n - l)

P.S. I decided not to split larger chunks for this function, but this was just a convenient simplification.

However, this seems very verbose given all the conduit functions that deal with chunking[1 https://www.fpcomplete.com/user/snoyberg/library-documentation/vectorbuilder,2 http://hackage.haskell.org/package/conduit-combinators-0.2.8.2/docs/Data-Conduit-Combinators.html,3 http://hackage.haskell.org/package/conduit-extra-1.1.3.2/docs/Data-Conduit-Binary.html,4 http://hackage.haskell.org/package/conduit-extra-1.1.3.2/docs/Data-Conduit-Blaze.html]. Please help! There must surely be a better way to do this using combinators, but I am missing some piece of intuition!

P.P.S. Is it ok to use lazy bytestring for the buffer as I've done? I'm a bit unclear about the internal representation for bytestring and whether this will help, especially since I'm using BL.length which I guess might evaluate the thunk anyway?


结论

只是为了详细说明迈克尔的回答和评论,我最终得到了这个管道:

import qualified Data.Conduit               as C
import qualified Data.Conduit.Combinators   as C
import qualified Data.ByteString            as B
import qualified Data.ByteString.Lazy       as BL

-- | "Strict" rechunk of a chunked conduit
chunksOfE' :: (MonadBase base m, PrimMonad base) 
         => Int 
         -> C.Conduit ByteString m ByteString
chunksOfE' chunkSize = C.vectorBuilder chunkSize C.mapM_E =$= C.map fromByteVector

我的理解是vectorBuilder将支付早期连接较小块的成本,将聚合块生成为严格的字节串。

据我所知,有一种替代实现可以产生惰性字节串块(即“大块大块”当聚合块非常大和/或馈入自然流接口(如网络套接字)时,()可能是理想的。这是我对“惰性字节串”版本的最佳尝试:

import qualified Data.Sequences.Lazy        as SL
import qualified Data.Sequences             as S
import qualified Data.Conduit.List          as CL

-- | "Lazy" rechunk of a chunked conduit
chunksOfE :: (Monad m, SL.LazySequence lazy strict)
          => S.Index lazy
          -> C.Conduit strict m lazy
chunksOfE chunkSize = CL.sequence C.sinkLazy =$= C.takeE chunkSize

这个怎么样?

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
import ClassyPrelude.Conduit

chunksOfAtLeast :: Monad m => Int -> Conduit ByteString m LByteString
chunksOfAtLeast chunkSize =
    loop
  where
    loop = do
        lbs <- takeCE chunkSize =$= sinkLazy
        unless (null lbs) $ do
            yield lbs
            loop

main :: IO ()
main =
    yieldMany ["hello", "there", "world!"]
        $$ chunksOfAtLeast 3
        =$ mapM_C print

根据您的目标,您可以采取许多其他方法。如果你想要一个严格的缓冲区,那么使用 vectorBuilder 的 blaze-builder 会很有意义。但这会保留您已有的相同类型签名。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用组合器将管道重新分成更大的块 的相关文章

  • 在 Haskell 中将 Maybe Int 转换为 Int

    我正在编写以下代码 并希望找到框字符串中数字的索引 所以我用了findIndex但它返回Maybe Int值 而我只想要Int value 我怎样才能转换Maybe Int to Int值或者有什么方法可以提取Int from Maybe
  • 由于标志字节串 -lt-0_10_4,无法使用 Stack 构建 hello world 程序

    通过生成一个裸露的 hello world 项目 stack new myproject simple 每当我跑步时stack setup stack init or stack build我总是出现以下错误 Downloading lts
  • 如何在 Haskell 中获得列表的中间位置?

    我刚刚开始使用 Haskel 学习函数式编程 我正在慢慢度过Erik Meijer 在 Channel 9 的讲座 http channel9 msdn com shows Going Deep Lecture Series Erik Me
  • 函数式编程是否需要新的命名约定?

    我最近开始使用 Haskell 学习函数式编程 并在 Haskell 官方 wiki 上发现了这篇文章 如何阅读哈斯克尔 http www haskell org haskellwiki How to read Haskell What t
  • 用parsec解析递归数据

    import Data Attoparsec Text Lazy import Data Text Lazy Internal Text import Data Text Lazy pack data List a Nil Cons a L
  • Haskell/GHC:使用相同模式匹配多个一元构造函数

    所以我正在尝试定义 TrieSet 数据类型 尽管我知道我不需要 http hackage haskell org package TrieMap module Temp where import Data Map data TrieSet
  • 如何让 Show 显示函数名称?

    作为一个让我熟悉 Haskell 的简单练习 在 Youtube 上闲逛并偶然进入美国倒计时游戏节目之后 我想为数字游戏制作一个求解器 你得到 6 个数字 需要将它们与 为了得到给定的结果 到目前为止我所得到的是非常脑死亡的 let ope
  • 为什么 Parsec 的 sepBy 停止并且不解析所有元素?

    我正在尝试解析一些逗号分隔的字符串 该字符串可能包含也可能不包含具有图像尺寸的字符串 例如 hello world 300x300 good bye world 我写了下面的小程序 import Text Parsec import qua
  • 在 Haskell 中计算移动平均线

    我正在学习 Haskell 所以我尝试实现移动平均函数 这是我的代码 mAverage Int gt Int gt Float mAverage x a fromIntegral k fromIntegral x k lt rawAvera
  • 在 Haskell 中增长数组

    我想在 Haskell 中实现以下 命令式 算法 给定一个序列对 e0 s0 e1 s1 e2 s2 en sn 其中 e 和 s 部分不一定是自然数不同的是 在每个时间步都会随机选择该序列的一个元素 例如 ei si 并根据 ei si
  • Haskell 类型系统的细微差别

    我一直在深入了解 haskell 类型系统的本质 并试图了解类型类的要点 我已经学到了很多东西 但我在下面的代码片段上遇到了困难 使用这些类和实例定义 class Show a gt C a where f Int gt a instanc
  • Haskell scala 互操作性

    我是 Scala 初学者 来自面向对象范式 在了解 Scala 的函数式编程部分时 我被引导到 Haskell 纯函数式编程语言 探索 SO 问题答案 我发现 Java Haskell 具有互操作性 我很想知道 Scala Haskell
  • 我应该在 Turtle 或 Foldl 包中使用折叠吗?

    我在使用 Turtle 时遇到了一些困难 直到盯着难以理解的错误消息几分钟后才意识到我使用了错误的fold功能 https hackage haskell org package turtle 1 5 8 docs Turtle Shell
  • Haskell:是的,没有类型类。为什么是整数?

    我有一个关于 GHCi 如何假定整数类型的问题 我正在阅读 Learn you a Haskell 是 否类型的课程 如果您想阅读全文 这里有一个链接 http learnyouahaskell com making our own typ
  • 纯函数怎么能做IO呢?

    我最近了解到莫纳德随机数 http hackage haskell org package MonadRandom 0 1 13 docs Control Monad Random Class html t 3aMonadRandom图书馆
  • Haskell,堆栈:找到可执行文件

    我正在寻找类似的东西 stack whereis hasktags where whereis行为或多或少类似于 UNIXwhereis命令 hasktags是这样运行的 stack exec hasktags stack exec whe
  • 找不到模块“Yesod”

    我有以下代码 LANGUAGE TypeFamilies QuasiQuotes MultiParamTypeClasses TemplateHaskell OverloadedStrings module Simple where imp
  • 这个对自身单位的列表理解是如何工作的?

    在 haskell IRC 频道中有人问 是否有一种简洁的方法来定义一个列表 其中第 n 个条目是之前所有条目的平方和 我认为这听起来像一个有趣的谜题 递归定义无限列表是我真正需要练习的事情之一 所以我启动了 GHCi 并开始尝试递归定义
  • Haskell - lambda 表达式

    我试图了解什么是有用的以及如何在 Haskell 中实际使用 lambda 表达式 我不太明白使用 lambda 表达式相对于定义函数的约定方式有何优势 例如 我通常会执行以下操作 let add x y x y 我可以简单地打电话 add
  • Haskell 输入返回元组

    我想知道 IO 函数是否可以返回元组 因为我想从这个函数中获取这些元组作为另一个函数的输入 investinput IO gt Char Int investinput do putStrLn Enter Username username

随机推荐