【发布时间】:2016-10-31 11:26:13
【问题描述】:
我有两个管道源 A 和 B,我想将它们合并为一个产生:
data Result = Left Int | Value Int | Right Int
merge :: Monad m => Source m Int -> Source m Int -> Source Result
merge a b = undefined
比如:
- 使用来自
a和b的值 - 执行一些计算以产生
Value Int - 作为计算的结果
a或b可能有一个leftover - 当其中一个序列用尽时,结果源应继续生成
Left或Right值(取决于哪个原始源仍有值),直到两个源都用尽为止
我尝试使用ZipSource 来实现它,例如:
getZipSource (ZipSource (a =$= CL.map Left) <* ZipSource (b =$= CL.map Right))
但我不知道如何让它在来源之间交替(当我做两个awaits 时)以及如何以我上面描述的方式处理剩菜。
我也查看了sequenceSources,但它似乎也没有帮助。
可以用 Conduit 构建类似的东西吗?
一个具体的例子是:
- 有两个(假定已排序)
Int来源 - 从两者中获取值并进行比较
- 产生
min值,从最大值中减去它,然后将剩余的值放回其流中 - 重复。
预期的输出是:
runConduit $ merge (CL.sourceList [10, 20, 30]) (CL.sourceList [6, 4, 20]) $$ CL.take 10
Value 6 -- 10-6 = 4, 6 yielded, 4 goes back to "a"
Value 4 -- 4-4 = 0, both values are fully consumed
Value 20 -- 20-20 = 0, both values are fully consumed
Left 30 -- "b" has no values, but "a" still yielding
[更新]
到目前为止,我发现的最好方法是编写类似于 zipSources 的内容,将其内部结构调整为:
go (Done ()) (HaveOutput src close y) = HaveOutput (go (Done ()) src) close (Nothing, Just y)
go (HaveOutput src close x) (Done ()) = HaveOutput (go src (Done ())) close (Just x, Nothing)
这会是正确的方法吗?
【问题讨论】:
-
你的方法看起来不错,虽然我没有测试过。您可能还想查看
ZipConduit,看看它是否符合您的要求。