【发布时间】:2011-10-07 05:35:45
【问题描述】:
Enumerator的定义是:
type Enumerator a m b = Step a m b -> Iteratee a m b
文档指出,Iteratees 消费数据,Enumerators 生产数据。我可以理解如何生成具有这种类型的数据:
enumStream :: (Monad m) => Stream a -> Enumerator a m b
enumStream stream step =
case step of
Continue k -> k stream
_ -> returnI step -- Note: 'stream' is discarded
(enumEOF 比这更复杂......它显然会检查以确保Iteratee 在被赋予Continue 之后不会Continue,如果它确实会抛出错误。)子>
即,Iteratee 在与runIteratee 一起运行时会产生Step。这个Step 然后被提供给我的枚举器,它为它提供一个Stream 以便它可以继续。我的枚举器返回结果延续。
有一点让我印象深刻:这段代码在Iteratee monad 中运行。这意味着它可以消耗数据,对吧?
-- | Like 'enumStream', but consume and discard a chunk from the input stream
-- simply because we can.
enumStreamWeird :: (Monad m) => Stream a -> Enumerator a m b
enumStreamWeird stream step = do
_ <- continue return -- Look, mommy, I'm consuming input!
case step of
Continue k -> k stream
_ -> returnI step
文档指出,当枚举器同时充当源和接收器时,应使用Enumeratee:
type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)
但是,显然我不必这样做;我可以在Enumerator 的定义中使用输入,正如我的enumStreamWeird 函数所示。
我的问题是:
如果您尝试像
enumStreamWeird那样“使用”Enumerator中的数据,会发生什么?数据从何而来?即使我们没有足够疯狂地使用枚举器中的数据,在底层 monad 中代表枚举器执行操作是否有效,而不是代表迭代器读取我们的数据再生产?
后一个问题可能与我的主要问题不太相关,但我试图了解 Enumerator 是如何做到的。
【问题讨论】: