2

シンクがあり、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
4

2 に答える 2

2

「部分的」の考え方は、継続関数を返すということです。つまり、さらに入力があると、その入力で継続を呼び出します。残りの行を入力ストリームに押し戻そうとするのは、入力の最初のビットを繰り返し解析するため、せいぜい無駄です。

パーサー関数をパラメーターとして受け取る関数を作成する必要があります。次に、部分的なケースは次のようになります

Partial c -> sink c

これにより、「シンク」はさらに入力を待機し、それを「c」関数に渡します。これにより、中断したところから新しい入力の解析が続行されます。

于 2014-11-09T20:54:40.123 に答える
1

Conduit には出力を連結するという概念がないことに注意してください。したがって、何が起こるかは次のとおりです。

  • コンジットは部分的な入力を取得します。
  • 解析するだけでは不十分です。
  • あなたは残り物としてそれを戻します。
  • コンジットは、元に戻したものと同じものを再度読み取ります。
  • そして、これは永遠に続きます。

パーサーを繰り返し試す方向を本当に追求したい場合は、残りの値を元に戻すたびに、前回よりも大きいことを確認する必要があります。したがって、次のようにします。パーサーが終了しない場合は、追加の入力を読み取り、それを既にある入力と連結し、これを残り物として押し戻し、再試行します。

上記の手順にはO(n^2)という複雑さがあることに注意してください。これは、大きなデータ ブロックを消費した後にパーサーが成功した場合に特に問題になります。一度に 1 文字を受け取る場合 (発生する可能性があります)、パーサーが 1000 文字を消費する必要がある場合、500000 処理ステップのようなものを取得します。したがって、Conduit と Attoparsec の間で提供されているバインディングを使用するか、自分で行いたい場合は、 によって提供される継続を適切に使用することを強くお勧めしますPartial

于 2014-11-11T19:08:06.333 に答える