如何使用Conduit组合器实现类似takeWhile的功能? [英] How to implement a takeWhile-like function using Conduit combinators?
问题描述
我正在尝试实现一个功能,该功能结合了 groupBy
和 takeWhile
的思想,并在内部使用后者.具体来说,它将所有在当前谓词上连续返回 True
的元素归为一个列表,然后对下一个谓词进行相同的操作,以此类推:
I'm trying to implement a function that combines the ideas of groupBy
and takeWhile
, as well as uses the latter internally. Specifically, it will group all elements that consecutively return True
on the current predicate as a list, then it will proceed to do the same with the next predicate, and so on:
takeWhileGrouped :: (Monad m, MonoFoldable mono) =>
([Element mono -> Bool]) -> ConduitT (Element mono) [Element mono] m ()
takeWhileGrouped preds = go preds
where
go (pred:nextPreds) = yield (goIter pred) >> go nextPreds
goIter pred = takeWhile pred .| sinkList
此实现很可能会遇到其他问题,但是在此阶段,我收到一个编译错误,不确定如何继续(为什么 mono0
无法用 mono
?);是因为缺少使用某种语言扩展名还是其他问题?
It's entirely likely this implementation suffers other issues, but at this stage I'm getting a compilation error that I'm not sure how to proceed with (why can't mono0
be identified with mono
?); is this due to the lack of using some language extension, or is there another issue?
• Couldn't match type ‘Element mono0’ with ‘Element mono’
Expected type: [Element mono -> Bool]
-> ConduitT (Element mono) [Element mono] m ()
Actual type: [Element mono0 -> Bool]
-> ConduitT (Element mono0) [Element mono0] m ()
NB: ‘Element’ is a non-injective type family
The type variable ‘mono0’ is ambiguous
• In the ambiguity check for ‘takeWhileGrouped’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature:
takeWhileGrouped :: (Monad m, MonoFoldable mono) =>
([Element mono -> Bool])
-> ConduitT (Element mono) [Element mono] m ()
|
140 | takeWhileGrouped :: (Monad m, MonoFoldable mono) =>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
更新1
启用 AllowAmbiguousTypes
确实会使错误消失,但是我会注意到在
Enabling AllowAmbiguousTypes
does make the error go away, but I'll note that in the combinators library this appears to be unnecessary.
现在真正的问题显现出来了:
Now the real issues show themselves:
• Couldn't match type ‘ConduitT a0 c0 m0 [b0]’
with ‘[Element mono]’
Expected type: ConduitT (Element mono) [Element mono] m ()
Actual type: ConduitT
(Element seq0) (ConduitM a0 c0 m0 [b0]) m ()
• In the expression: go preds
In an equation for ‘takeWhileGrouped’:
takeWhileGrouped preds
= go preds
where
go (pred : nextPreds) = yield (goIter pred) >> go nextPreds
goIter pred = takeWhile pred .| sinkList
• Relevant bindings include
preds :: [Element mono -> Bool]
(bound at src/FDS/Data/Conduits.hs:143:18)
takeWhileGrouped :: [Element mono -> Bool]
-> ConduitT (Element mono) [Element mono] m ()
(bound at src/FDS/Data/Conduits.hs:143:1)
|
143 | takeWhileGrouped preds = go preds
| ^^^^^^^^
• Couldn't match type ‘seq -> seq’ with ‘ConduitT a b m1 ()’
Expected type: ConduitM a b m1 ()
Actual type: seq -> seq
• Probable cause: ‘takeWhile’ is applied to too few arguments
In the first argument of ‘(.|)’, namely ‘takeWhile pred’
In the expression: takeWhile pred .| sinkList
In an equation for ‘goIter’:
goIter pred = takeWhile pred .| sinkList
• Relevant bindings include
pred :: Element seq -> Bool
(bound at src/FDS/Data/Conduits.hs:146:12)
goIter :: (Element seq -> Bool) -> ConduitM a c m1 [b]
(bound at src/FDS/Data/Conduits.hs:146:5)
|
146 | goIter pred = takeWhile pred .| sinkList
| ^^^^^^^^^^^^^^
更新2
我使用了错误的 takeWhile
,现在使用了来自Conduit Cominators的 CC.takeWhile
,我目前的位置是:
I was using the wrong takeWhile
, now using CC.takeWhile
from Conduit Cominators, I'm currently left with:
• Couldn't match type ‘ConduitT
(Element mono) c0 m0 [Element mono]’
with ‘[Element mono]’
Expected type: ConduitT (Element mono) [Element mono] m ()
Actual type: ConduitT
(Element mono) (ConduitM (Element mono) c0 m0 [Element mono]) m ()
• In the expression: go preds
In an equation for ‘takeWhileGrouped’:
takeWhileGrouped preds
= go preds
where
go (pred : nextPreds) = yield (goIter pred) >> go nextPreds
goIter pred = CM.takeWhile pred .| sinkList
• Relevant bindings include
preds :: [Element mono -> Bool]
(bound at src/FDS/Data/Conduits.hs:144:18)
takeWhileGrouped :: [Element mono -> Bool]
-> ConduitT (Element mono) [Element mono] m ()
(bound at src/FDS/Data/Conduits.hs:144:1)
|
144 | takeWhileGrouped preds = go preds
| ^^^^^^^^
更新3
需要解决一些组合程序API问题,但至少还有一个问题:
Had a few combinator API issues to fix, but at least one still remains:
takeWhileGrouped :: forall m mono. (Monad m, MonoFoldable mono) =>
([Element mono -> Bool]) -> ConduitT (Element mono) [Element mono] m ()
takeWhileGrouped preds = go preds
where
go (pred:nextPreds) = yieldM (goIter pred) >> go nextPreds
go [] = yield []
goIter :: (Element mono -> Bool) -> m ([Element mono])
goIter pred = (CC.takeWhile pred) .| sinkList & runConduitRes
出乎意料的是,我在 takeWhile
的输入中弹出一个()
:
Unexpectedly, I have a ()
popping up in the input to takeWhile
:
• Couldn't match type ‘Element mono’ with ‘()’
Expected type: () -> Bool
Actual type: Element mono -> Bool
• In the first argument of ‘CC.takeWhile’, namely ‘pred’
In the first argument of ‘(.|)’, namely ‘(CC.takeWhile pred)’
In the first argument of ‘(&)’, namely
‘(CC.takeWhile pred) .| sinkList’
• Relevant bindings include
pred :: Element mono -> Bool
(bound at src/FDS/Data/Conduits.hs:148:12)
goIter :: (Element mono -> Bool) -> m [Element mono]
(bound at src/FDS/Data/Conduits.hs:148:5)
preds :: [Element mono -> Bool]
(bound at src/FDS/Data/Conduits.hs:144:18)
takeWhileGrouped :: [Element mono -> Bool]
-> ConduitT (Element mono) [Element mono] m ()
(bound at src/FDS/Data/Conduits.hs:144:1)
|
148 | goIter pred = (CC.takeWhile pred) .| sinkList & runConduitRes
| ^^^^
更新4
修复了更多的逻辑和类型错误后,通过添加内部类型注释(CC.takeWhile curPred :: ConduitT(Element mono)(Element mono)m())
确实有帮助,我有一些可以编译的东西,但是仍然需要测试:
After fixing some more logic and type errors, which was really aided by adding an internal type annotation (CC.takeWhile curPred :: ConduitT (Element mono) (Element mono) m ())
, I have something that compiles, but still needs testing:
takeWhileGrouped :: forall m mono. (Monad m, MonoFoldable mono) =>
([Element mono -> Bool])
-> ConduitT () (Element mono) m ()
-> ConduitT (Element mono) [Element mono] m ()
takeWhileGrouped preds conIn = go preds
where
go (curPred:nextPreds) = yieldM (goIter curPred) >> go nextPreds
go [] = yield []
goIter :: (Element mono -> Bool) -> m ([Element mono])
goIter curPred = conIn .| CC.takeWhile curPred .| sinkList & runConduit
推荐答案
I came to the eventual conclusion that, if I wanted to implement this component, I couldn't do it in terms of component composition (fusion).
这似乎是可行的实现:
takeWhileGrouped :: forall m mono. Monad m =>
[Element mono -> Bool] -> ConduitT (Element mono) [Element mono] m ()
takeWhileGrouped preds = start
where
start = await >>= maybe (return ()) (loop preds [])
loop :: [(Element mono) -> Bool] -> [Element mono] -> (Element mono)
-> ConduitT (Element mono) [Element mono] m ()
loop [] _ _ = yield []
loop curPreds@(predF:predRest) accum x =
await >>= maybe (yield accumX) go
where
accumX = if predF x then x:accum else accum
go y = if predF y then loop curPreds accumX y
else yield accumX >> loop predRest [] y
This design was influenced by the most similar function I knew of (though from a deprecated library), groupBy.
这篇关于如何使用Conduit组合器实现类似takeWhile的功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!