4

私は現在、私の小さなプロジェクトのためにいくつかの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つの可能性は、(本格的なパイプではなく)単項アクションを取ることかもしれません.

4

1 に答える 1

7

もしよろしければ、このように選択を説明することで、これに関する皆さんの考えを整理するのに役立つと思います. 次のいずれか:

  1. /Pipe内のレイヤー:EitherTErrorT

    どちらかT e (Pipe abm) r

  2. /Pipeの外側のレイヤー:EitherTErrorT

    パイプ ab (EitherT em) r

前者のアプローチが必要です。これには、MonadError のインスタンスにすることができるという優れたプロパティもあります (それが必要な場合)。

2 つのアプローチの違いを理解するために、2 番目のアプローチはパイプライン全体のレベルでエラーをスローします。最初のものは、個々のパイプの粒度でエラー処理を許可し、構成されたパイプを正しく処理します。

次に、いくつかのコードについて説明します。よろしければ、EitherT の方が使いやすいので、EitherT を使用します。

import Control.Error
import Control.Pipe

type PipeE e a b m r = EitherT e (Pipe a b m) r

runPipeE = runPipe . runEitherT

p1 <?< p2 = EitherT (runEitherT p1 <+< runEitherT p2)

次に、PipeE 内で catchT と throwT を心ゆくまで使用します。

このアプローチには、パイプラインの特定のセグメントに選択的に適用できるという別の利点がありますが、他のパイプで構成する前に、潜在的な例外的な値を処理する必要があります。その柔軟性を利用して、パイプラインのさまざまな段階でさまざまな型の例外的な値を使用したり、失敗できない段階ではまったく使用しないようにして、それらの段階のエラー チェックのオーバーヘッドを回避したりできます。

于 2012-07-10T16:33:27.953 に答える