流式处理库中如何处理总和编码

3
这个问题的动机是这样的场景-我们有一系列的值,这些值由Sum编码表示。假设我们用Either ByteString ByteString来表示字节流在错误和良好状态下的情况。现在,我们有另一个函数可以压缩ByteString流。是否可能在Either ByteString ByteString输入流上运行此函数,并压缩其中任何一个(不仅仅是Right,而是在Left被产生而不是Right时也可以压缩Left)。compress函数类型的签名如下(我使用Streaming库):
compress ::  MonadIO m 
         =>  Int 
         -- ^ Compression level.
         -> Stream (Of ByteString) m r
         -> Stream (Of ByteString) m r 

我们的输入流类型为Stream (Of (Either ByteString ByteString)) m r。那么,是否有一种转换函数可以在输入流上运行compress,并输出一个类型为Stream (Of (Either ByteString ByteString)) m r的流,其中两者都被压缩了。
对我来说,我觉得我应该编写一个自定义的compress,比如说eitherCompress,如下所示:
eitherCompress :: MonadIO m 
             =>  Int 
             -- ^ Compression level.
             -> Stream (Of (Either ByteString ByteString)) m r
             -> Stream (Of (Either ByteString ByteString)) m r 

这是否正确?如果是这种情况,使用从zstd库中的以下函数编写eitherCompress的好方法是什么:

compress :: Int 
         -- ^ Compression level. Must be >= 1 and <= maxCLevel.
         -> IO Result    

我已经使用 yield 编写了流生产者,但是我只为简单情况实现了它们,其中输入只是一个源,而不是一个流。非常感谢您对此问题的帮助。

1个回答

2
解决这些情况的常见技巧是将每个加数分别放在不同的单子层中(因此会有两个流层),单独操作每个层,然后要么分别消耗它们,要么将它们重新合并成一个层。
首先,有两个辅助函数,它们使用maps将其转换为和从Sum函子组合的形式:
toSum :: Monad m 
      => Stream (Of (Either ByteString ByteString)) m r 
      -> Stream (Sum (Of ByteString) (Of ByteString)) m r
toSum = maps $ \(eitherBytes :> x) -> 
    case eitherBytes of
        Left bytes -> InL (bytes :> x)
        Right bytes -> InR (bytes :> x)

fromSum :: Monad m 
        => Stream (Sum (Of ByteString) (Of ByteString)) m r 
        -> Stream (Of (Either ByteString ByteString)) m r
fromSum = maps $ \eitherBytes ->
    case eitherBytes of
        InL (bytes :> x) -> Left bytes :> x
        InR (bytes :> x) -> Right bytes :> x

我们这样做是为了能够使用分离取消分离功能。
实际的压缩函数应该是:
eitherCompress :: MonadIO m 
               => Int 
               -> Stream (Of (Either ByteString ByteString)) m r 
               -> Stream (Of (Either ByteString ByteString)) m r
eitherCompress level =
     fromSum . unseparate . hoist (compress level) . compress level . separate . toSum

“hoist”用于在最上层以下的单子层上工作。

完美,这正是我在寻找的!我在文档中看到了sum编码,但一直没有能够将各个部分拼凑起来,直到你指出了toSumfromSum方法。 - Sal
问题 - 如果“compress”专门针对具体的返回类型(例如Stream(Of ByteString)m(),而不是r,我们现在有了()),那么由于forall量词,hoist将无法工作。在这种情况下,什么可以替代“hoist”? - Sal
@Sal 我不知道该如何在那种情况下替换 hoist - danidiaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接