如何在管道haskell中添加新的源

时间:2012-02-10 11:06:07

标签: haskell conduit

使用network-conduit时,我遇到以下代码问题:

import Data.Conduit.List as CL
import Data.Conduit.Text as CT
import qualified Data.ByteString.Char8 as S8
import qualified Data.Text as TT

mySource :: ResourceT m => Integer -> Source m Int
mySource i = {- function -} undefined

myApp :: Application
myApp src snk = 
    src $= CT.decode CT.ascii
        $= CL.map decimal
        $= CL.map {-problem here-}
        $$ src

在问题所在地我想写一些像

这样的东西
\t -> case t of
    Left err = S8.pack $ "Error:" ++ e
    Right (i,xs) = (>>>=) mySource 
                 {- or better: 
                   do 
                   (>>>=) mySource
                   (<<<=) T.pack xs
                  -}

(>>>=)函数将mySource输出推送到下一级别       (<<<=)正在将功能发送回上一级

1 个答案:

答案 0 :(得分:1)

网络将字节流切换为任意ByteString块。使用上面的代码,这些ByteString块将映射到Text的块,并且Text的每个块将被解析为decimal。但是,表示单个decimal的一串十进制数字可以分成两个(或更多)Text个块。此外,正如您所知,使用decimal会返回Text块的剩余部分,这些块未作为decimal的一部分进行解析,而您正试图将其推回到输入流。

使用Data.Conduit.Attoparsec. conduitParserEitherData.Attoparsec.Text.decimal可以解决这两个问题。请注意,仅仅解析decimal是不够的;你还需要处理decimal之间的某种分隔符。

由于Source的类型签名是

,因此也无法从CL.map拼接CL.map
map :: Monad m => (a -> b) -> Conduit a m b

您传递给map的功能有机会将每个输入a转换为单个输出b,而不是b的流。为此,您可以使用awaitForever,但是您需要将Source转换为使用Producer的常规toProducer,以便匹配类型。

但是,在您的代码中,您尝试将解析错误发送到ByteString的下游,但mySource的输出为Int,这是一个类型错误。在这两种情况下,您必须提供ByteString的流;成功的解析案例可以通过融合其他Conduit来返回Conduit,只要它最终输出ByteString

...
$= (let f (Left err) = yield $ S8.pack $ "Error: " ++ show err
        f (Right (_, i)) = toProducer (mySource i) $= someOtherConduit
    in awaitForever f)

其中someOtherConduitInt中吸取mySource,并ByteString来源。

someOtherConduit :: Monad m => Conduit Int m ByteString

最后,我认为您的意思是连接管道末尾的snk而不是src