如何在管道haskell内添加新源
我在使用 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
输出推到下一个级别的内容,并且 (<<<=)
正在将函数发送回上一级
I have a problem with the following code using 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
in problem place I want to write something like
\t -> case t of
Left err = S8.pack $ "Error:" ++ e
Right (i,xs) = (>>>=) mySource
{- or better:
do
(>>>=) mySource
(<<<=) T.pack xs
-}
where the (>>>=)
function pushes mySource
output to the next level and(<<<=)
is sending function back to previous level
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
网络将字节流分割成任意的
ByteString
块。通过上面的代码,这些ByteString
块将被映射到Text
块,并且每个Text
块将被解析为十进制。但是,表示单个
小数
的十进制数字字符串可以分为两个(或更多)Text
块。此外,正如您所意识到的,使用十进制可以返回未解析为十进制部分的剩余文本块,您正试图将其推回到输入流中。这两个问题都可以通过使用 Data.Conduit.Attoparsec 来解决。 PipelineParserEither 与 Data.Attoparsec.Text.decimal。请注意,仅解析十进制是不够的;您还需要处理小数点之间的某种分隔符。
也不可能从
CL.map
拼接Source
,因为CL.map
的类型签名是您传递给 < code>map 有机会将每个输入
a
转换为单个输出b
,而不是b
的流。为此,您可以使用awaitForever
,但您需要使用toProducer
将Source
转换为通用Producer
code> 以使类型匹配。但是,在您的代码中,您尝试将解析错误作为
ByteString
发送到下游,但将mySource
的输出作为Int
发送,这是一个类型错误。在这两种情况下,您都必须提供 ByteString 流;成功的解析案例可以返回一个通过融合其他Conduit
而成的Conduit
,只要它最终得到ByteString
的输出:其中 < code>someOtherConduit 从
mySource
接收Int
,并源ByteString
。最后,我相信您的意思是连接管道末端的
snk
而不是src
。The network chops up the byte stream into arbitrary
ByteString
chunks. With the code above, thoseByteString
chunks will be mapped to chunks ofText
, and each chunk ofText
will be parsed as adecimal
. However, a string of decimal digits representing a singledecimal
may be split across two (or more)Text
chunks. Also, as you realize, usingdecimal
gives you back the remainder of theText
chunk that didn't get parsed as part of thedecimal
, which you are trying to shove back into the input stream.Both of these problems can be solved by using
Data.Conduit.Attoparsec. conduitParserEither
withData.Attoparsec.Text.decimal
. Note that it is not sufficient to just parsedecimal
; you will also need to handle some kind of separator betweendecimal
s.It is also not possible to splice a
Source
fromCL.map
, sinceCL.map
's type signature isThe function you pass to
map
gets an opportunity to transform each inputa
into a single outputb
, not a stream ofb
's. To do that, you can useawaitForever
, but you'll need to transform yourSource
into a generalProducer
withtoProducer
in order for the types to match.However, in your code, you are trying to send parse errors downstream as
ByteString
's, but the output ofmySource
asInt
's, which is a type error. You must provide a stream ofByteString
in both cases; the successful parse case can return aConduit
made by fusing otherConduit
's as long as it ends up with an output ofByteString
:where
someOtherConduit
sinks theInt
's frommySource
, and sourcesByteString
's.Finally, I believe you meant to connect the
snk
at the end of the pipe instead of thesrc
.