Haskell 如何使用导管组合器实现takeWhile类函数?
我正在尝试实现一个函数,它结合了Haskell 如何使用导管组合器实现takeWhile类函数?,haskell,conduit,Haskell,Conduit,我正在尝试实现一个函数,它结合了groupBy和takeWhile的思想,并在内部使用后者。具体来说,它将把当前谓词上连续返回True的所有元素分组为一个列表,然后对下一个谓词执行相同的操作,依此类推: takeWhileGrouped :: (Monad m, MonoFoldable mono) => ([Element mono -> Bool]) -> ConduitT (Element mono) [Element mono] m () ta
groupBy
和takeWhile
的思想,并在内部使用后者。具体来说,它将把当前谓词上连续返回True
的所有元素分组为一个列表,然后对下一个谓词执行相同的操作,依此类推:
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
?);这是因为没有使用某种语言扩展,还是有其他问题
• 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
确实会消除错误,但我会注意到,在这种情况下似乎没有必要
现在真正的问题显示出来了:
• 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
,现在使用的是来自导管Cominators的CC.takeWhile
,我现在只剩下:
• 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
有几个combinator API问题需要解决,但至少还有一个问题:
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
的输入中弹出了一个()
:
• 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::conduit(Element mono)(Element mono)m())
,我有一些可以编译的东西,但仍然需要测试:
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
我得出的最终结论是,如果我想实现这个组件,(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
这个设计受到了我所知道的最相似的功能的影响(尽管来自一个不推荐使用的库)。我最终得出结论,如果我想实现这个组件,(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
这个设计受到了我所知道的最相似的函数的影响(尽管来自一个不推荐使用的库)。我仍然想知道如何使用
await
实现这个功能。我仍然想知道如何使用await