这个问题背后的动机是这种情况 - 我们有一个由 Sum
编码表示的值流。让我们假设 Either ByteString ByteString
分别表示处于错误状态和良好状态的字节流。现在,我们有另一个可以压缩 ByteString 流的函数。是否可以在 Either ByteString ByteString
输入流上运行此函数,并压缩其中一个(不仅是 Right
,还可以压缩 Left
,以防 产生 >Left
而不是 Right
)。下面是 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
编写了stream
生成器,但我已经在输入只是源而不是流的简单情况下实现了它们。非常感谢您对这个问题的帮助。
最佳答案
解决这些情况的常见技巧是将总和的每个分支放在不同的单子(monad)层中(因此将有两个流层)分别操作每个层,然后单独使用它们或将它们重新加入到单个层中层。
首先是两个辅助函数,使用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
我们这样做是为了能够使用 separate
和 unseparate
功能。
实际的压缩函数是:
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
用于处理最顶层下面的一元层。
关于haskell - 处理流媒体库中的和编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49224990/