34

EnumeratorsConduits、およびPipesの基本的な違いと、主な利点と欠点について、自分よりも深く理解している人から聞きたいです。一部の議論はすでに 進行中ですが、大まかな概要を把握できれば幸いです。

4

2 に答える 2

28

抽象化としての列挙子/反復子は、Oleg Kiselyov によって発明されました。これらは、予測可能な (低い) リソース要件で IO を実行するクリーンな方法を提供します。現在の Enumerators パッケージは、Oleg のオリジナル作品にかなり近いものです。

Yesod Web フレームワーク用にコンジットが作成されました。私の理解では、それらは非常に高速になるように設計されています。ライブラリの初期バージョンは非常にステートフルでした。

エレガンスを重視したパイプ。それらは、複数ではなく 1 つのタイプ、フォーム モナド (トランスフォーマー) およびカテゴリ インスタンスを持ち、設計上非常に「機能的」です。

カテゴリ的な説明が好きな場合:Pipe型は、次の信じられないほど単純なファンクター上のフリー モナドです。

data PipeF a b m r = M (m r) | Await (a -> r) | Yield b r
instance Monad m => Functor (PipeF a b m) where
   fmap f (M mr) = M $ liftM mr
   fmap f (Await g) = Await $ f . g
   fmap f (Yield b p) = Yield b (f p)
--Giving:
newtype Pipe a b m r = Pipe {unPipe :: Free (PipeF a b m) r}
  deriving (Functor, Applicative, Monad)

--and
instance MonadTrans (Pipe a b) where
   lift = Pipe . inj . M

実際のパイプ定義ではこれらが組み込まれていますが、この定義の単純さは驚くべきものです。(<+<) :: Monad m => Pipe c d m r -> Pipe a b m r -> Pipe a d m rパイプは、最初のパイプを受け取り、yieldsそれを待機中の 2 番目のパイプに供給する 操作の下にカテゴリを形成します。

Conduits(状態の代わりに CPS を使用し、単一の型に切り替える)より似たものに移行しているように見えますがPipe、パイプはより良いエラー処理のサポートを獲得しており、おそらくジェネレーターとコンシューマーに別々の型を返すようになっています。

このエリアは急速に動いています。私は、これらの機能を備えたパイプ ライブラリの実験的なバリアントをハッキングしてきました。他の人も同様であることを知っています (Hackage の Guarded Pipes パッケージを参照)。行う。

私の推奨事項: Yesod を使用している場合は、Conduits を使用してください。成熟したライブラリが必要な場合は、列挙子を使用します。エレガンスを第一に考えている場合は、パイプを使用してください。

于 2012-04-03T01:45:54.963 に答える
7

3 つのライブラリすべてを使用してアプリケーションを作成した後、私が目にした最大の違いは、リソースのファイナライズの処理方法にあると思います。たとえば、パイプはリソースのファイナライズをフレームとスタックの別々のタイプに分割します。

入力リソースだけでなく、潜在的に出力リソースをファイナライズする方法についても、まだいくつかの議論があるようです。たとえば、DB から読み取り、ファイルに書き込む場合、DB の接続を閉じる必要があるだけでなく、出力ファイルをフラッシュして閉じる必要があります。パイプラインに沿って例外や失敗のケースを処理する方法を決定するとき、物事は複雑になります。

もう 1 つの微妙な違いは、列挙子パイプラインの戻り値の処理方法と計算方法です。

これらの違いと潜在的な矛盾の多くは、パイプのモナドとカテゴリの実装を使用することで明らかになり、現在コンジットに組み込まれています。

于 2012-07-16T15:35:16.783 に答える