私は現在、私の小さなプロジェクトのためにいくつかのpipes-core/attoparsec配管を書いています。ByteString
各パーサーが、パーサーへの入力を待機し、解析された値を生成する (パーサーを再起動する)パイプを提供するようにします。したがって、エラー処理がなければ、次のようなタイプになります
parserP :: Monad m => Parser a -> Pipe ByteString a m r
さて、解析エラーをどうするかわかりません。私の現在のアイデアは次のとおりです。
- 戻り値の型にエラーを追加する (つまり
Either ParseError r
、 だけではなく で値を返すr
) - モナドがエラー処理メカニズムを提供することを要求する (つまり、モナドがパイプを引き継いで実装することを要求する
MonadError
) - モナドの Pipe を引き継ぐことにより、モナドにエラーメカニズムを
ErrorT e m a
提供させるm
- パラメーターを追加して、ユーザーが動作を指定できるようにします ( のようなもの
(ParseError -> P.Pipe ByteString a m r)
で、解析エラーの場合は提供されたパイプにバインドするだけです)。
エラー処理にパイプの戻り値の型を使用することは、ハックのように見えるため、最初の解決策は間違っているようです。一つには、それはパイプとの構成を醜くし、多かれ少なかれ最終的な解決策に取り込まれているように見えます (tryAwait を使用して値の待機を停止することにより、ダウンストリーム パイプがエラーから回復できるようにする能力を失う可能性は別として) ?)。
2 番目の解決策は間違っているように見えますが、その理由はよくわかりません。おそらく、 ParseError をモナドが持つエラータイプに変換するパラメーターを取得する必要があるためです(モナドに を実装する必要がある場合を除きますMonadError ParseError
。これにより、多くの簿記が必要になるようです)。最後に、あまり見た覚えがないようですMonadError
。これは、使用に何らかの問題があることを示唆しています。
パイプは、解析エラーを気にすることになっていないユーザー指定のモナド(IO)を持つパイプラインの一部になるため、3番目の解決策は私の場合に機能します(ネットワークデータを解析して、ユーザーに与えられた形式にします指定されたタイプ)。しかし、それはそれほど洗練されているようには見えません。また、(おそらく?) 他のコンテキストで使用されると、多くの簿記が必要になります。
最終的な解決策についてはあまり考えていませんが、やや複雑なようです。
この特定のケースについての考え (私が道を外れて明らかな何かを見逃していても、まったく驚かないでしょう)、およびパイプでのエラー処理に関する議論への (多かれ少なかれ関連する) 参照に感謝します( -core)/conduits/interatee など
編集: もう1つの可能性は、(本格的なパイプではなく)単項アクションを取ることかもしれません.