質問

パフォーマンスを向上させるために、Parsecを使用してAttoparsecを使用する機能するHaskellコードを変換しています。私は変更を加えました、そしてすべてがコンパイルされますが、私のパーサーは正しく機能しません。

さまざまなレコードタイプで構成されるファイルを解析しています。レコードまたはコメントを解析するための私の個々の機能はそれぞれ正しく機能しますが、レコードのシーケンスをコンパイルするための関数を作成しようとすると、パーサーはより多くの入力を期待しているため、常に部分的な結果を返します。

これらは、私が試した2つの主なバリエーションです。どちらも同じ問題を抱えています。

items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine

この2番目のものについては、レコード/コメントパーサーを変更して、終了文字を消費しました。

items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput

私のアプローチに何か問題がありますか?私が試みていることを達成する他の方法はありますか?

役に立ちましたか?

解決

私は以前にこの問題に遭遇しましたが、私の理解は、それがその方法によって引き起こされているということです <|> の定義で機能します sepBy:

sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
    where scan = liftA2 (:) p ((s *> scan) <|> pure [])

これはにのみ移動します pure [] 一度 (s *> scan) 失敗しましたが、これはあなたが入力の終わりにいるからといって起こりません。

私の解決策は、ただ電話することでした feedempty のバイテストリング Result によって返されます parse. 。これは一種のハックかもしれませんが、それも attoparsec-iteratee 問題を扱っています:

f k (EOF Nothing)  = finalChunk $ feed (k S.empty) S.empty

私が知ることができる限り、これは唯一の理由です attoparsec-iteratee ここと平凡な古いもので働いています parse そうではありません。

他のヒント

故障する前にできるだけ多くの入力を消費するattoparsecパーサーを書く場合は、入力の終了に到達したときに部分的な結果の継続を伝える必要があります。

あなたはかなり少ない情報を提供しているので、私はあなたに良い助けを与えるのが難しいと思います。しかし、私が与えたいコメントがいくつかあります:

  • おそらく、パーサーは、入力が完了していることを認識しておらず、EOLを取得するか、別のレコードを取得することにかかっています。したがって、部分的な結果を求めます。それが強制することを期待して、EOLに相当するものを与えてみてください。
  • コードを覚えていませんが、代替インスタンスを使用することはパフォーマンスの解析に有害な場合があります。その場合は、コメントとRecordTypesでケースを付けたい場合があります。
  • 私は多くのバイナリ解析にシリアルを使用していますが、それも非常に高速です。 attoparsecはテキストパーサーのように優れているようです。あなたは間違いなくオプションを考慮する必要があります。
  • もう1つのオプションは、長期的にIterateeベースのIOを使用することです。 John Latoは、最新のMonad Reader(Issue#16 I Believe)でIterateesに関する優れた記事を作成しました。ライン終了条件は、信号の反復です。しかし、反復タイプは非常に困難であり、慣れるのに少し時間がかかることに注意してください。
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top