使用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
输出推送到下一级别
(<<<=)
正在将功能发送回上一级
答案 0 :(得分:1)
网络将字节流切换为任意ByteString
块。使用上面的代码,这些ByteString
块将映射到Text
的块,并且Text
的每个块将被解析为decimal
。但是,表示单个decimal
的一串十进制数字可以分成两个(或更多)Text
个块。此外,正如您所知,使用decimal
会返回Text
块的剩余部分,这些块未作为decimal
的一部分进行解析,而您正试图将其推回到输入流。
使用Data.Conduit.Attoparsec. conduitParserEither
和Data.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)
其中someOtherConduit
从Int
中吸取mySource
,并ByteString
来源。
someOtherConduit :: Monad m => Conduit Int m ByteString
最后,我认为您的意思是连接管道末尾的snk
而不是src
。