我有两个管道源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 Inta或b都可以有一个leftoverLeft或Right值(取决于原始源仍然有值),直到两个源都耗尽为止。我尝试用ZipSource实现它,例如:
getZipSource (ZipSource (a =$= CL.map Left) <* ZipSource (b =$= CL.map Right))但是,我不知道如何使它在源之间交替(当我执行两个await),以及如何以我前面描述的方式处理剩菜。
我也看过sequenceSources,但它似乎也没有帮助。
这样的东西能用管道建造吗?
一个具体的例子是:
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)这是正确的方法吗?
发布于 2016-11-04 06:18:07
我就这样做了:
data MergedValue a v b = BackL a v | MergedValue v | BackR v b
data JoinResult a v b = LeftoverL a | JoinValue v | LeftoverR b
joinSources :: Monad m
=> (a -> b -> MergedValue a v b)
-> Source m a
-> Source m b
-> Source m (JoinResult a v b)
joinSources f as bs =
go (newResumableSource as) (newResumableSource bs)
where
go ras rbs = do
(ras', ma) <- lift $ ras $$++ await
(rbs', mb) <- lift $ rbs $$++ await
case (ma, mb) of
(Nothing, Nothing) -> pure ()
(Nothing, Just b) -> yield (LeftoverR b) >> go ras' rbs'
(Just a, Nothing) -> yield (LeftoverL a) >> go ras' rbs'
(Just a, Just b) -> case f a b of
BackL x v -> do
yield (JoinValue v)
(nxt, _) <- lift $ ras' $$++ leftover x
go nxt rbs'
BackR v x -> do
yield (JoinValue v)
(nxt, _) <- lift $ rbs' $$++ leftover x
go ras' nxt
MergedValue v -> yield (JoinValue v) >> go ras' rbs'https://stackoverflow.com/questions/40341242
复制相似问题