7

attoparsecパーサーConduitを使用してを作成しようとしています。具体的には、を与えられて、パーサーを入力に繰り返し適用し、結果をストリーミングするを構築したいと思います。parseOne :: Parser TConduit ByteString m T

attoparsec-conduitは、をに変換sinkParserすることを提案しますが、どうすればこれをに変換できますか?私が探しているのは、次のような関数です。ParserSinkSinkConduit

conduitSink :: (Resource m) => Sink a m b -> Conduit a m b

これは、データをに繰り返しフィードしSink、各結果を生成します。手動ループとしてはかなり簡単に書けるようですが、もっと良い方法があるのではないかと思います。

コンジットライブラリにこの一見明らかな機能がないため、私は何か間違ったことをしているのではないかと思います。これを達成するためのより良い方法はありますか?ユースケースは、生のバイトをメッセージベースのネットワークプロトコルの解析された形式に変換し、パイプラインの後の段階で処理することです。blaze-builder-conduitのConduit T m ByteStringおかげで、私はすでに反対の方向(つまり)を持っているので、これは物事を構造化する最も自然な方法のように思えました。

4

1 に答える 1

6

SequencedSinkこれにはシステムを使用する必要があります。シンクと追跡された状態を使用して、シンク プロデューサーの繰り返し適用からコンジットを生成します。

作成したシンクは、コンジット シーケンスの最後の結果となる1 つの値を段階的に解析するように最適化されています。

ただし、これをコンジット パイプラインの一部にする必要があり、着信の各チャンクがByteStringパーサーと 1 回または複数回一致する場合と一致しない場合があるため、解析プロセスをよりきめ細かく制御するように注意する必要があります。シンクのすべてのアプリケーション間の不完全な解析の状態。

たとえば、パーサーが解析などを行い、解析されたダッシュの数を示していると仮定すると、[--][----]TようIntにパーサーの状態を追跡する必要があります。

Input chunk    Sink result - Data.Conduit.SequencedSinkResponse
[--][---]      Emit Nothing [2, 3]
[---][---      Emit (Just #func) [3]
---------      Emit (Just #func) []
]              Emit Nothing [12]
               Stop

この場合、Maybe (ByteString -> Data.Attoparsec.ByteString.Result)渡された状態として使用します。状況によっては、別のデータ型の方が適している場合があります。

この明示的なストリーム処理は、コンジットのパイプラインの性質を維持するために必要です。パーサー コンジットを「ボトルネック」にして、チャンクごとにパーサーを満たすのに十分なデータを常に待機させると、主要なパフォーマンス シンクになります。

必要なシンクの実装は、利用可能なResourceTモナド インターフェイスを使用するとかなり簡単です。

編集:シンクをループに適用するだけが最も簡単な解決策ですが、パーサーがバイトチャンクの境界で終わることが多い短いスニペットを解析する場合、パフォーマンス特性がわずかに異なります。

于 2012-01-28T04:52:22.073 に答える