这个问题背后的动机是这个场景 - 我们有一个由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
我使用stream
编写了yield
个生成器,但我已经针对输入只是源而不是流的简单情况实现了它们。非常感谢帮助解决这个问题。
答案 0 :(得分:2)
解决这些情况的一个常见技巧是将总和的每个分支放在不同的monadic层(因此将有两个流层)分别操作每个层,然后单独使用它们或者将它们重新连接到一个层中层
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
用于处理最顶层下面的monadic层。