Haskell 如何使用iteratee库的最新版本(撰写本文时为0.8.1.2)?

Haskell 如何使用iteratee库的最新版本(撰写本文时为0.8.1.2)?,haskell,iterate,Haskell,Iterate,我已经阅读了关于迭代器和枚举器概念的教程,并实现了一个示例版本,作为学习它们如何工作的一种方式。但是,iteratee包中使用的类型与我找到的任何教程都有很大的不同。例如,Iteratee被定义为: Iteratee runIter :: forall r. (a -> Stream s -> m r) -> ((Stream s -> Iteratee s m a) -> Maybe SomeExce

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

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

我真的不明白我该怎么办。是否有任何关于使用此版本的教程,以及为什么这样编写(即与Oleg最初的编写方式相比有什么好处)。

免责声明:我对迭代对象了解不多,也从未使用过。所以请接受我的回答 一言为定

这个定义相当于Oleg(更准确地说,它是 一个CPS风格的总和),带有一个扭曲:它保证访问 iteratee总是返回一个一元值

以下是Oleg的定义:

 data Iteratee el m a =
   | IE_done a
   | IE_cont (Maybe ErrMsg)
             (Stream el -> m (Iteratee el m a, Stream el))
data Iteratee el m a =
  forall r.
    (a -> r) ->
    ((Maybe ErrMsg), (Stream el -> m (Iteratee el m a, Stream el)) -> r) ->
     r
所以这是一个完成的的总和,我们完成了一个给出的,作为结果, 或者
cont(可能是ErrMsg)(流el->…)
:继续 迭代给出了另一个输入块,可能是一个错误(在 在这种情况下,继续延续相当于重新启动 计算)

众所周知,
a b
相当于所有r的
。(a->
r) ->(b->r)->r
:给你
a
b
相当于 向您保证,对于
r
上的任何结果
a
和变换 你可能会想到的
b
,我将能够制作这样一个
r
(到 这样做我必须有一个
a
b
)。从某种意义上说,(a或b) 引入一个数据,并
r。(a->r)->(b->r)->r
这个数据:如果这样一个函数被命名为
case\u ab
,那么
case\u ab(\a->
foo_a)(\b->foo_b)
等同于模式匹配
案例
对于某些
ab::要么a b
,{Left a->foo_a;Right b->foo_b}的ab

这里是延续(我们在这里谈论延续是因为
(a->r)
表示“一旦我们知道值是正确的,它将发生什么变化?” 相当于Oleg定义的
a
”):

 data Iteratee el m a =
   | IE_done a
   | IE_cont (Maybe ErrMsg)
             (Stream el -> m (Iteratee el m a, Stream el))
data Iteratee el m a =
  forall r.
    (a -> r) ->
    ((Maybe ErrMsg), (Stream el -> m (Iteratee el m a, Stream el)) -> r) ->
     r
但是迭代对象定义中有一个扭曲(对一些无害的定义进行模化) 咖喱):结果不是
r
,而是
mr
:在某种意义上,我们强制 我们的迭代对象上的模式匹配结果始终存在于单子中
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(迭代..,流..)
,而在 iteratee包它只是
流->iteratee
。我想他们 我们在这里删除了monad,因为他们在外部级别强制执行它 (如果您应用iteratee,您将被迫住在monad中,因此 为什么还要强制后续计算在monad中?)。我不 知道为什么不再有
输出了吗,我想这意味着 当输入可用时,这些迭代对象必须使用所有输入 (或在返回类型
a
中对“尚未完成”逻辑进行编码)。也许
这是为了提高效率。

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

您可能会发现iteratee目录中的一些文件有助于理解如何使用该库;这可能是最容易遵循的

基本上,用户不需要使用
runIter
,除非您正在创建自定义枚举。迭代者可以通过组合提供的原语来创建,也可以使用
liftI
idone
icont
函数来创建,经过枚举,然后使用
run
tryRun
运行


Oleg有两个“原始”版本和一个CPS版本(可能还有其他版本)。原始版本都在。第一个是实际代码,第二个是注释。第一个需要一些特殊的函数,
>==
$$
,以代替通常的
>=
$
。第二个可以使用标准函数,但不幸的是,很难用这个版本来解释一元排序。还有一些其他的缺点。CPS版本避免了所有这些问题,这就是为什么我选择了iteratee。我还发现用这种风格定义的迭代器更短,可读性更强。不幸的是,我不知道有任何特定于CPS版本的教程,但是可能有用。

谢谢,我没有意识到
a b
之间的关系对于所有r。(a->r)->(b->r)->r
。这对理解图书馆有很大帮助。作为实验,我在上做了一些代码来演示这种关系(如果你愿意,你可以将代码添加到你的文章中,因为它很好地演示了这种关系);他最近改了。在iteratee所基于的版本中,定义的第一个分支是
IE_done a(Stream el)
,未完成的iteratee必须使用所有可用输入。我还没有决定是否在“iteratee”中进行此更改;我不确定在CPS转换后它是否非常有用,这将是一个巨大的破坏。谢谢,示例程序和Oleg对IteratorMCPS.hs的评论非常有用,特别是在这个库中没有教程的情况下。