0

我将使用 C# 语法,因为我熟悉它,但它并不是真正特定于语言的。


假设我们想提供一个 API 来检查 aTree并对每个Node.

解决方案 1:void Visit(Tree tree, Action<Node> action)
它需要一个tree, 并调用action树中的每个节点。

解决方案 2:IEnumerable<Node> ToEnumerable(Tree tree)
它转换tree为一个扁平的惰性序列,这样我们就可以遍历并调用action每个节点。


现在,让我们看看如何将一种 API 转换为另一种。

Visit在以下基础上提供非常简单ToEnumerable

void Visit(Tree tree, Action<Node> action) {
    ToEnumerable(tree).ForEach(action);
}

但是,是否有任何语言的概念/功能可以提供ToEnumerableVisit作为惰性序列,因此不会提前创建列表)?

4

3 回答 3

0

如果您正在编写将访问每个节点的代码(如使用树),则可以让迭代器为每个分支调用迭代器,并yield return在叶节点上执行 a。这种方法可行,而且非常简单,但有一个严重的缺点,即很容易得到可读性很强但执行速度很慢的代码。该站点上的其他一些问题和答案将提供有关如何在迭代器中有效地遍历树的见解。

如果“树”只是一个示例,而您真正拥有的是一个类,该类公开了一个例程以在每个节点上调用某个委托(类似于List.ForEach()),但不公开IEnumerable,您可以使用前者来生成a List,然后您可以对其进行迭代。使用类似的东西var myList = new List<someThing>(); myCollection.ForEach( (x) => myList.Add(x) );,然后你就可以枚举myList.

如果这还不够,因为添加到列表中的对象在枚举完成时可能无效,在极少数情况下可能会使用多线程来完成所需的操作。例如,如果您有两个已排序的集合,其ForEach方法准备每个项目以供使用,执行指定的操作,然后在继续下一个项目之前清理每个项目,并且如果您需要交错对来自两个独立集合的项目的操作,一个可能能够在单独的线程上迭代集合,并使用同步原语,因此每个线程将根据需要等待另一个线程。

请注意,仅通过ForEach方法公开自身的集​​合很容易在执行此类 a 期间限制访问ForEach(如果不需要这种限制,他们可能会实现IEnumerable)。一个人调用的“项目操作”可能会在同一线程上的同一集合上ForEach执行另一个操作,因为后者必须在前者恢复之前完成。但是,当一个线程正在运行时,尝试在第二个线程上调用 a 可能会发生故障或等待第一个操作完成。如果第一个在第二个之前等待某个动作,就会导致死锁。正因为如此,多线程的场景比简单地构建一个ForEachForEachForEachForEachForEachList很少见。尽管如此,在少数情况下它可能会有所帮助(例如,上面提到的独立集合上的“拉链”操作)。

于 2012-07-13T14:58:44.190 回答
0

Not sure if I understand you correctly, but in Python, you can create iterable interface on any object. So you would just add special method __iter__ (which will yield nodes while traversing the tree). The visit procedure is then just about iterating through Tree object and calling action on each node.

于 2012-07-13T13:27:06.143 回答
0

我想现在我明白了这个想法。我在这里需要的概念称为一流的延续,或者特别是call/cc。对我来说令人困惑的是,C# 已经在 中提供了这个概念的有限实现yield return,但它不适用于我的场景。

因此,如果 C# 提供完整的实现,解决方案将如下所示:

IEnumerable<Node> ToEnumerable(Tree tree) {
    tree.Visit(node => magic yield return node);
}

wheremagic yield return不是从node => ...lambda 返回序列,而是从 . 返回下一个元素ToEnumerable

但是,这个答案仍然不完整,因为我没有看到 和 之间的确切相关yield returncall/cc。当我理解这一点时,我会更新答案。

于 2012-07-14T13:25:33.670 回答