我发现Data.Conduit.List
模块中缺少以下函数,我找不到使用该模块中的函数来组合它的简单方法。
takeWhile :: Monad m => (a -> Bool) -> Consumer a m [a]
takeWhile p = await >>= \case
Nothing -> return []
Just b -> if p b
then (b :) <$> takeWhile p
else (leftover b) >> return []
此功能在我的应用程序中非常有用,我有时需要将下几个项目组合在一起,而且我不确定有多少项目。
这个函数的缺失对我来说有点奇怪,因为有take :: Monad m => Int -> Consumer a m [a]
和groupBy :: Monad m => (a -> a -> Bool) -> Conduit a m [a]
,但没有takeWhile
。
我错过了什么吗?
编辑:根据@ ErikR的请求,这里有两个简单的例子,可以说明我认为这个功能有用的原因。
情况1:协议指定流中有标题部分。为简单起见,我们假设它是String
流,标题项由前导@
标记。
流内容:
@language=English
@encoding=Unicode
Apple
Orange
Blue
Red
Sheep
Dog
...
使用takeWhile
的代码:
myConduit :: Conduit String IO String ()
myConduit = do
headers <- takeWhile ((== '@') . head)
awaitForever $ \ item -> do
case getLanguage headers of
English -> ...
French -> ...
案例2:协议指定前缀为@
的项目有几个以+
为前缀的延续。
流内容:
Apple
Orange
Blue
@Has
+kell
@A
+Really
+Long
+Word
Dog
...
使用takeWhile
的代码:
myConduit :: Conduit String IO String ()
myConduit = runMaybeC . forever $ do
a <- maybe (lift mzero) return =<< await
aConts <- if head item == '@' then takeWhile ((== '+') . head)
else return []
liftIO . putStrLn . concat $ a : aConts
然而,除了有用之外,它也是为了完整性。我看到Data.Conduit.List
的目标是在Conduit上下文中提供一组“类似列表”的操作。我认为应该提供像takeWhile
这样的面包和黄油功能,以及像dropWhile
这样的兄弟姐妹,以便人们在将管道视为列表时不必改变他们的编码风格。 / p>