【问题标题】:Haskell enumerator: analog to iteratees `enumWith` operator?Haskell 枚举器:类似于 iteratees `enumWith` 运算符?
【发布时间】:2011-10-05 01:23:08
【问题描述】:

今天早些时候,我为 iteratee 编写了一个小型测试应用程序,它组成了一个 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]

在查看枚举器库时,我没有看到 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]

第一个复制文件,但不显示进度;第二个显示进度,但不复制文件,所以显然内置 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

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

编辑

似乎没有内置的方法可以做到这一点。 Haskell 邮件列表上有关于添加 enumSequencemanyToOne 之类的组合器的讨论,但到目前为止,枚举器包中似乎没有任何东西提供此功能。

【问题讨论】:

  • 我没有花足够长的时间查看文档来制定和测试真正的答案,但表面上看起来 Enumerators 和 Enumeratees 可以按照您想要的方式组合。 (P.S. 我猜你说的是 Hackage 上的“枚举器”包。你真的应该在前面说这样的话,因为现在有六种不同的迭代器实现。=)
  • 你也没有花足够的时间阅读我的问题。
  • 这有点粗鲁,考虑到我刚刚花了一点我的时间帮助你解决你的问题。也许你可以指出你认为我错过的部分,而不是讽刺。
  • 如果您查看我的代码 cmets,您会看到我清楚地说明了代码 sn-p 使用哪个库的哪个版本,您还会看到我已经很清楚什么我正在尝试编写的是迭代器,而不是枚举器或枚举器,文档确实显示了如何组合。我并不是要粗鲁,但如果您想提供帮助,您应该阅读整个问题并理解它,而不是仅仅告诉我 RTFM,我显然已经这样做了。如果答案这么明显,为什么要花 3 天时间才能有人说“它在手册中”?
  • 哈!您对库版本绝对正确。对此我很抱歉——我的眼睛往往会从 cmets 上移过,我想这一次真的咬了我一口。但是,我认为您并不明确知道可以组成枚举数。事实上,最后两句话,“我想知道……组成迭代器……是不是不可能开箱即用。一般公认的正确方法是什么?”可以有意义地回答“普遍接受的正确方法是组合枚举器而不是迭代器”。很抱歉,这对您没有帮助。

标签: haskell enumerator


【解决方案1】:

在我看来,与其试图让两个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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2013-03-05
    • 1970-01-01
    • 2021-03-02
    • 2011-04-12
    • 1970-01-01
    • 2019-10-05
    相关资源
    最近更新 更多