2011-07-14 7 views
6

今日、私は、実際にデータをコピーするためのイテレータを使って進行を記述するためのイテレータを作成したイテレータのための小さなテストアプリケーションを書いています。私はこれらのような値で巻き取る:ハスケルの列挙子:iterateesの `enumWith`演算子に似ていますか?

-- NOTE: this snippet is with iteratees-0.8.5.0 
-- side effect: display progress on stdout 
displayProgress :: Iteratee ByteString IO() 

-- side effect: copy the bytestrings of Iteratee to Handle 
fileSink :: Handle -> Iteratee ByteString IO() 

writeAndDisplayProgress :: Handle -> Iteratee ByteString IO() 
writeAndDisplayProgress handle = sequence_ [fileSink handle, displayProgress] 

列挙子のライブラリを見て、私はsequence_またはenumWithのアナログ表示されません。私がしたいのは、iterateesを2つ作成して1つのものとして動作させることだけです。私は結果を破棄することができます(とにかく()になるでしょう)、それを保つ、私は気にしません。 (& & &)のControl.Arrowが私が望むのは、矢印ではなくイテレートだけです。

私は、これらの二つのオプションを試みた:

-- NOTE: this snippet is with enumerator-0.4.10 
run_ $ enumFile source $$ sequence_ [iterHandle handle, displayProgress] 
run_ $ enumFile source $$ sequence_ [displayProgress, iterHandle handle] 

最初の1つのコピーのファイルを、しかし、進行状況が表示されません。 2番目のファイルは進捗状況を示していますが、ファイルはコピーされませんので、列挙子のiterateesに組み込まれたsequence_の効果は、終了するまで最初のiterateeを実行してから、もう一方を実行することです。私はイテレートをシリアルではなく並列で実行したい。私は何かを明らかに欠けているような気がしますが、列挙子ライブラリのwc例を読んで、私はこの好奇心コメントを参照してください。この発言は、組み合わせまたは列挙型のフレームワークISN内iterateesを構成することを示している場合、私は疑問に思う

-- Exactly matching wc's output is too annoying, so this example 
-- will just print one line per file, and support counting at most 
-- one statistic per run 

を箱から出ることはできません。これを行う一般的に受け入れられる正しい方法は何ですか?

編集

これを行うには、組み込みの方法はありませんかのように思えます。 enumSequencemanyToOneのようなコンビネータの追加についてのHaskellメーリングリストの議論がありますが、これまで実際にこの機能を提供する列挙子パッケージには何も存在していないようです。

+0

私は本当の答えを策定し、テストするためのドキュメントを見て十分な長費やすことはありませんでしたが、それは表面的に '' Enumerator'sとEnumeratee'sのように見えますが、あなたが望む方法で構成可能です。 (PS:Hackageの "列挙子"パッケージについてお話していると思いますが、今のように何かと言うべきでしょう。今はiterateesの半ダースの実装があるからです。) –

+0

あなたはまた、私の質問を読むのに十分な時間。 –

+0

これはちょっと失礼ですが、あなたの問題を解決するのにちょっと時間を費やしたと考えています。皮肉なことをする代わりに、私が逃したと思う部分を指摘することができます。 –

答えて

2

Iteratees 2つを並行して使用しようとするよりも、ストリームをID番号Enumerateeに渡すほうが簡単です。

ここでは、ファイルをコピーし、各チャンクの後にコピーされたバイト数を出力する簡単な例を示します。

import System.Environment 
import System.IO 
import Data.Enumerator 
import Data.Enumerator.Binary (enumFile, iterHandle) 
import Data.Enumerator.List (mapAccumM) 
import qualified Data.ByteString as B 

printBytes :: Enumeratee B.ByteString B.ByteString IO() 
printBytes = flip mapAccumM 0 $ \total bytes -> do 
    let total' = total + B.length bytes 
    print total' 
    return (total', bytes) 

copyFile s t = withBinaryFile t WriteMode $ \h -> do 
    run_ $ (enumFile s $= printBytes) $$ iterHandle h 

main = do 
    [source, target] <- getArgs 
    copyFile source target