2

我已经阅读了关于迭代器和枚举器概念的教程,并实现了一个示例版本作为学习它们如何工作的一种方式。但是,iteratee 包中使用的类型与我找到的任何教程都非常不同。例如,Iteratee定义为:

Iteratee     
   runIter :: forall r. (a -> Stream s -> m r) 
           -> ((Stream s -> Iteratee s m a) 
           -> Maybe SomeException -> m r) 
           -> m r

我真的不明白我的意思是这样做。是否有任何关于使用此版本的教程,以及为什么以这种方式编写(即这与 Oleg 的原始方式相比有什么好处)。

4

2 回答 2

2

免责声明:我是 iteratee 的当前维护者。

您可能会发现 iteratee示例目录中的一些文件有助于理解如何使用该库;word.hs可能是最容易理解的。

runIter基本上,除非您正在创建自定义枚举,否则用户不需要使用。Iteratees 可以通过组合提供的原语来创建,也可以与liftIidoneicont函数组合,枚举,然后使用runor运行tryRun

Oleg 有两个“原始”版本和一个 CPS 版本(可能还有其他版本)。原始版本都在http://okmij.org/ftp/Haskell/Iteratee/IterateeM.hs中。第一个是实际代码,第二个在注释中。第一个需要一些特殊功能,>>==and$$来代替通常的>>=and $。第二个可以使用标准函数,但不幸的是,这个版本很难推理一元排序。还有一些其他的缺点。CPS 版本避免了所有这些问题,这就是我切换 iteratee 的原因。我还发现以这种风格定义的迭代器更短且更具可读性。不幸的是,我不知道任何特定于 CPS 版本的教程,但是Oleg 的评论可能有用。

于 2011-04-23T19:02:15.767 回答
1

免责声明:我不太了解迭代器,也从未使用过它们。所以,我的回答持保留态度。

这个定义等同于 Oleg 的(更准确地说,它是 CPS 风格的求和),但有一点不同:它保证访问迭代对象总是返回一个单子值。

这是奥列格的定义:

 data Iteratee el m a =
   | IE_done a
   | IE_cont (Maybe ErrMsg)
             (Stream el -> m (Iteratee el m a, Stream el))

所以它是两者的总和done a,我们完成了一个给a定的结果,或者cont (Maybe ErrMsg) (Stream el -> ...):一种在给定另一块输入的情况下继续迭代的方法,并且可能是一个错误(在这种情况下继续继续相当于重新开始计算)。

众所周知,这Either a b相当于forall r. (a -> r) -> (b -> r) -> r:给你一个ab相当于向你保证,对于你可能想出的任何结果r转换a和转换,我将能够产生这样一个(要做到这一点,我必须有一或一)。从某种意义上说,(Either ab) 引入了一个数据,并消除了 这个数据:如果这样的函数被命名为,那么就相当于对 some进行模式匹配。brabr. (a -> r) -> (b -> r) -> r case_abcase_ab (\a -> foo_a) (\b -> foo_b)case ab of { Left a -> foo_a; Right b -> foo_b }ab :: Either a b

所以这里是延续(我们在这里谈论延续是因为 (a -> r)表示“一旦我们知道它是一个值会发生什么a”)相当于奥列格的定义:

data Iteratee el m a =
  forall r.
    (a -> r) ->
    ((Maybe ErrMsg), (Stream el -> m (Iteratee el m a, Stream el)) -> r) ->
     r

但是 iteratee 的定义有一个转折(以一些无害的柯里化为模):结果不是rbut m r:在某种意义上,我们强制我们的 iteratee 上的模式匹配结果始终存在于 monad 中 m

data Iteratee el m a =
  forall r.
    (a -> m r) ->
    (Maybe ErrMsg -> (Stream el -> m (Iteratee el m a, Stream el)) -> m r) ->
     m r

最后,请注意 Oleg 定义中的“继续迭代”数据是Stream .. -> m (Iterate .., Stream ..),而在 iteratee 包中它只是Stream -> Iteratee。我假设他们在这里删除了 monad,因为他们在外部级别强制执行它(如果您应用 iteratee,您将被迫生活在 monad 中,那么为什么还要强制后续计算生活在 monad 中?)。我不知道为什么Stream不再有输出,我想这意味着那些 Iteratee 必须在可用时消耗所有输入(或在返回类型中编码“尚未完成”逻辑a)。也许这是出于效率原因。

于 2011-04-23T10:25:50.567 回答