让我们说我们需要总结存储在文件中的数字组,其中组由空行分隔。所以
1
2
3
4
5
结果是6 9
。
使用嵌套管道对此进行建模似乎很自然:外部管道会将线条分成线组,其中每个组本身都是源。
但是,我不会直接在导管中看到这种风格。用导管做这个最惯用的方法是什么?
答案 0 :(得分:2)
我建议有两种基本方法。简单的一个就是产生一个总和类型流,表示“另一个值”与“换行符”。另一种方法是使用组合方法,如withLine或foldLines。后者可以建立在前者之上。最初讨论了这种方法in a blog post on foldLines。
下面是一个完整的代码片段,显示了总和类型和组合方法。请注意,折叠(可能是一个坏名称)是一个通用函数,用于从sum类型转换为“嵌套流”。管道(基于FreeT IIRC)采用的方法也可能被管道使用,但正如我在博客文章中提到的,我认为这是一个比需要更复杂的解决方案。
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
import ClassyPrelude.Conduit
import Data.Text.Read (decimal, signed)
sumType :: Monad m => Conduit Text m (Maybe Int)
sumType =
linesUnboundedC =$= mapMC toMaybeInt
where
toMaybeInt "" = return Nothing
toMaybeInt t =
case signed decimal t of
Right (i, "") -> return $ Just i
_ -> fail $ "Invalid int: " ++ show t
folded :: Monad m => Sink a m () -> Sink (Maybe a) m ()
folded perGroup =
startGroup
where
startGroup = peekC >>= maybe (return ()) (const go)
go = takeMaybes =$ (perGroup >> sinkNull) >> startGroup
takeMaybes = await >>= maybe (return ()) (\x ->
case x of
Nothing -> return ()
Just y -> yield y >> takeMaybes)
main :: IO ()
main = do
let src = yield "1\n2\n3\n\n5\n6\n\n\n7"
src $$ sumType =$ (sinkList >>= print)
src $$ sumType =$ folded (sinkList >>= print)