9

我见过的 Scala 中 Iteratee 模式的 3 个描述都包括 3 个输入案例。例如,来自詹姆斯:

sealed trait Input[+E]
object Input {
  case object EOF extends Input[Nothing]
  case object Empty extends Input[Nothing]
  case class El[+E](e: E) extends Input[E]
}

更多详细信息请参见JamesRunarJosh的博客。

我的问题很简单:为什么需要Empty输入案例?

迭代模式定义了值流的生产者和消费者之间的关系。直观地说,如果任何输入为空,“运行”迭代器的生产者应该简单地折叠该空项,并且在非空输入可用之前不调用迭代器。

我注意到基于 pull 的 iteratees 类比,更熟悉的迭代器,没有定义一个空的情况,尽管元素可能已经在迭代器的“内部”被过滤掉了。

trait Iterator[E] {
    next: E        // like El
    hasNext: Boolean  //like EOF
}

虽然上述所有博客都提到需要一个 Empty 输入,但他们没有明确讨论为什么不能完全消除它。我注意到显示的示例迭代器将空输入视为无操作。

我真的很想要一个带有代码的示例,说明一个看似合理的“现实世界”问题,需要 Empty 输入消息来解决。

4

2 回答 2

3

假设您连接了一个枚举器,该枚举器将一些元素提供给迭代器,该peek迭代器查看第一个元素并返回它但不使用它,从而将其留给可能由 . 组成的另一个迭代器使用peek。然后你会想要提供一种机制peek来放回元素。从 Play 和 Scalaz iteratee 中我可以看出,完成的iteratee 只是为了这个目的而接受了一个参数。所以你可以在伪代码中做类似的事情:done(Some(result), El(result)). 请参阅peek 的这个实现

现在,如果您实现类似head实际消耗元素的东西,那么感觉就像一种方法是返回done(Some(result), emptyInput)以指示输入已被消耗。

另请参阅playframework 源代码中的此注释,显示 Done(_, _) 的第二个参数用于未使用的输入并初始化为空默认值。如此空旷的东西很少使用,很难找到现实世界的例子。它确实是实现迭代器的关键。事实上,看看哪些 iteratee 框架没有 empty 以及它们如何实现 peek 和 head 可能会很有趣。

于 2013-06-25T05:26:46.710 回答
2

James Roper在这里给出了一个有用的回应,包括我觉得有趣的这个片段:

我想它可以实现的另一种方式是将 Option[Input] 作为 Done 的剩余输入。这将使实现迭代更简单,因为它们不需要处理空。

于 2013-07-03T03:38:11.653 回答