Haskell 如何使用iteratee库的最新版本(撰写本文时为0.8.1.2)?
我已经阅读了关于迭代器和枚举器概念的教程,并实现了一个示例版本,作为学习它们如何工作的一种方式。但是,iteratee包中使用的类型与我找到的任何教程都有很大的不同。例如,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
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的评论非常有用,特别是在这个库中没有教程的情况下。