我正在寻找一个函数与以下签名(我认为):
partialProcessConduit :: forall m a b r. Monad m
=> (a -> (b, Maybe (ConduitT () a m ()) ))
-> ConduitT b Void m r
-> ConduitT () a m ()
-> m (r, ConduitT () a m ())
partialProcessConduit splitFunc consumingConduit sourceConduit
字符串
它基本上做了以下事情:
1.从管道sourceConduit
中重复获取a
类型的值。
1.将函数splitFunc
转换为a
。
1.将值b
从splitFunc
推入consumingConduit
1.如果splitFunc
返回Just (some conduit)
(即不是Nothing
),则返回对的第二部分
1.“close up”consumingConduit
,得到结果值r
1.返回带有sourceConduit
的“rest”的导管,但导管位于其前面的Just中。
我实际上已经实现了一些接近这一点的东西(提前为蹩脚的命名道歉)。
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Conduit (ConduitT, SealedConduitT, unsealConduitT, ($$+), await)
import Data.Void (Void)
import qualified Control.Arrow as Arrow
import Data.DList (DList)
partialProcessConduitInMemory :: forall m a b r. Monad m
=> (a -> (b, Maybe (ConduitT () a m ())))
-> (DList b -> r)
-> ConduitT () a m ()
-> m (r, ConduitT () a m ())
partialProcessConduitInMemory splitFunc collapseDList sourceConduit = do
(sc :: SealedConduitT () a m (), (result :: r, leftOver :: ConduitT () a m ())) <- x
pure (result, leftOver >> unsealConduitT sc)
where
x :: m (SealedConduitT () a m (), (r, ConduitT () a m ()))
x = sourceConduit $$+ g
g :: ConduitT a Void m (r, ConduitT () a m ())
g = Arrow.first collapseDList <$> go mempty
go :: DList b -> ConduitT a Void m (DList b, ConduitT () a m ())
go blockList = await >>= \case
Nothing -> pure (blockList, pure ())
Just block -> case splitFunc block of
(transformedBlock, Nothing) -> go $ blockList <> pure transformedBlock
(transformedBlock, Just leftOver) -> pure (blockList <> pure transformedBlock, leftOver)
型
这几乎是我想要的。注意这里的类型签名与上面的相同,除了第二个参数。这里,不是传递一个使用元素作为第二个参数的管道接收器,而是在一个DList中收集它们。我宁愿使用管道接收器来使用管道源的第一部分,而不是收集列表中的所有元素并处理它们。 我可以在这里使用管道接收器而不是
DList吗?如果可以,我需要做什么样的调整?我想在
go循环中将元素推入接收器中,而不是仅仅追加它们,然后执行
runConduit以获得结果
r`,但我无法很好地处理类型。任何帮助都很感激。
1条答案
按热度按时间crcmnpdw1#
我猜你想要这样的东西:
字符串
这里的
loop
管道的类型为ConduitT a b m (Maybe (ConduitT () a m ())
,因此它输入a
s并输出b
s,直到f
(也称为splitFunc
)返回前缀管道,在这种情况下,它返回Just
管道。如果splitFunc
从不返回管道,则返回Nothing
。现在,我们可以使用
fuseBoth loop snk
,它的类型为ConduitT a Void m (Maybe (ConduitT () a m (), r)
。这将b
s从loop
接收到snk
,返回来自splitFunc
的前缀管道(如果有的话)和来自snk
的返回值r
。最后,我们可以
src $$+ fuseBoth loop snk
。这将运行整个管道,从src
中提取a
s,并将b
s下沉到snk
中,直到splitFunc
返回前缀管道,此时它将返回:型
令人难以置信的是,密封管道是
src
的剩余部分,Maybe
管道是splitFunc
返回的“前缀”管道,最后的r
是snk
的返回值。剩下的就是将它们粘合在一起成为适当的返回值。这似乎是按照以下测试工作:
型
这将产生:
型
看起来是对的