我有一个接收器,想要在其中使用attoparsec进行一些解析。碰巧我得到Partial
结果。所以我认为我可能只是使用leftover
将不足的内容放回上游,以便稍后再添加更多内容。但是没有像我希望的那样添加新内容。我非常感谢有关如何解决这个问题的任何建议。谢谢!
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.IO.Class (liftIO)
import Data.Conduit
import qualified Data.Conduit.List as CL
import qualified Data.ByteString.Char8 as BS
import Data.Attoparsec.Char8
main = (CL.sourceList [BS.pack "foo", BS.pack "bar"]) $$ sink -- endless loop
-- this works:
-- main = (CL.sourceList [BS.pack "foobar"]) $$ sink
sink :: Sink BS.ByteString IO ()
sink = awaitForever $ \str -> do
liftIO $ putStrLn $ BS.unpack str -- debug, will print foo forever.
case (parse (string "foobar") str) of
Fail _ _ _ -> do
liftIO $ putStr $ "f: " ++ BS.unpack str
sink
Partial _ -> do
leftover str
sink
Done rest final -> do
liftIO $ putStr $ "d: " ++ show final ++ " // " ++ show rest
sink
答案 0 :(得分:2)
" Partial"是它返回一个延续函数;也就是说,一旦你有更多输入,你就可以用该输入调用continuation。试图将剩余的行重新推送到输入流是浪费,因为你反复解析输入的第一位。
您需要编写函数以将解析器函数作为参数。那么你的部分案例应该是
Partial c -> sink c
这将导致"沉没"等待更多输入,然后将其交给" c"函数,它将继续从中断处解析新输入。
答案 1 :(得分:0)
请记住,Conduit没有连接输出的概念。那么会发生什么:
如果您真的想要追求重复尝试解析器的方向,那么您需要确保每次将剩余的值恢复到比前一次更大的值。所以你要做这样的事情:如果解析器没有完成,请阅读其他输入,将其与您已有的输入连接起来,将其作为剩余部分再次推回并重试。
请注意,上述过程具有复杂性 O(n ^ 2),如果您的解析器在使用大量数据后成功,则会出现特别的问题。如果您一次只能接收一个字符(可能会发生)并且解析器需要消耗1000个字符,那么您将获得500000个处理步骤。所以我强烈建议使用Conduit和Attoparsec之间提供的绑定,或者,如果你想自己做,请正确使用Partial
提供的延续。