2012-04-02 10 views
33

基本的な違いがEnumerators,ConduitsPipesの間の主な違いとそのメリットと欠点を理解しています。いくつかはdiscussion's alreadyongoingですが、詳細な概要を知っておくとよいでしょう。列挙子対電線対パイプの長所と短所は何ですか?

+4

コンジットおよびパイプは依然として大幅に改訂されているため、解決するまで比較およびコントラストを行うことは困難です。理想的な状況では、導管とパイプは、列挙者を行う正しい方法に統合されます。 –

答えて

28

抽象としての列挙子/イテレータは、Oleg Kiselyovによって考案されました。予測可能な(低い)リソース要件でIOを行うきれいな方法を提供します。現在のEnumeratorsパッケージは、Olegのオリジナルの作業にかなり近いものです。

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

パイプは優雅さに焦点を当てます。それらは、モナド(変圧器)とカテゴリインスタンスをいくつかの型の代わりに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はより良いエラー処理と、おそらくジェネレータとコンシューマのための別々の型の返還を得ている間に、Pipeのようになります(状態の代わりにCPSを使用し、単一の型に切り替えるようです) 。

この領域は急速に移動しています。私は、これらの機能を備えたPipeライブラリの実験的な変形についてハッキングしています。他の人も同様です(HackageのGuarded Pipesパッケージを参照)が、Gabriel(Pipesの著者)行う。

私の推奨事項:Yesodを使用している場合、コンジットを使用してください。成熟したライブラリが必要な場合は列挙子を使用します。主にエレガンスを気にしている場合は、Pipeを使用してください。

7

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

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

もう1つ微妙な違いは、列挙子パイプラインの戻り値がどのように処理され、計算されるかのようです。

これらの相違点と潜在的な不一致は、MonadとCategoryの実装をパイプで使用することによって明らかになりましたが、現在はConduitsに入っています。

関連する問題