Haskell枚举器:模拟迭代`enumWith`运算符?

Dan*_*ons 6 haskell enumerator

今天早些时候,我为iteratees编写了一个小型测试应用程序,该应用程序组成了一个iteratee,用于使用iteratee编写进度来实际复制数据.我结束了这样的价值观:

-- 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]
Run Code Online (Sandbox Code Playgroud)

在查看枚举器库时,我没有看到类似的sequence_enumWith.我想要做的就是编写两个迭代,以便它们作为一个整体.我可以放弃结果(()无论如何)或保留它,我不在乎.来自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]
Run Code Online (Sandbox Code Playgroud)

第一个复制文件,但不显示进度; 第二个显示进度,但不复制文件,所以很明显内置sequence_对枚举器迭代的影响是运行第一个迭代直到它终止然后运行另一个,这不是我想要的.我希望并行运行迭代,而不是串行运行.我觉得我错过了一些明显的东西,但在阅读wc枚举器库的示例时,我看到了这个好奇的评论:

-- 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
Run Code Online (Sandbox Code Playgroud)

我想知道这句话是否表明在枚举框架中组合或组合迭代是不可能开箱即用的.普遍接受的正确方法是什么?

编辑:

似乎没有内置的方法来做到这一点.关于添加像enumSequencemanyToOne这样的组合器的Haskell邮件列表的讨论,但到目前为止,在枚举器包中似乎没有提供此功能的任何内容.

ham*_*mar 2

在我看来,与其尝试让两个Iteratees并行使用序列,不如通过一个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
Run Code Online (Sandbox Code Playgroud)