4

我编写了一段漂亮、优雅 (IMO) 的代码,我想移植到其他语言,如 C++、Java 等。

我面临的问题是双重的:

  • 代码使用yield
  • 代码高度递归

手动摆脱yield可能的,但非常乏味——这个过程非常机械化,显然是可自动化的。
同时,C# 编译器将其转换成的状态机非常丑陋——它实际上无法用于移植。(我试过反编译它;它只是不可读。)

我想知道,除了花几天时间手动摆脱之外,我还有其他选择yield吗?
或者是否有某种工具可以将yield块转换为(可读)状态机,然后我可以像普通代码一样移植?


如果你好奇我所说的“高度递归”是什么意思——下面的代码基本上是代码的结构(实际只有大约 66 行;它不是一个非常长的函数):

static IEnumerable<ReturnType> MyRecursiveYielder(args)
{
    if (blah1) yield return foo;
    else if (blah2)
        foreach (var foo1 in foo2.Blah())
            foreach (var item in MyRecursiveYielder(moreArgs))
                yield return item;
    else
    {
        var state = new State();
        foreach (var item in blah)
            foreach (var item2 in MyRecursiveYielder(otherArgs))
                foreach (var item3 in blah3)
                {
                    foreach (var result in MyRecursiveYielder(yetMoreArgs)))
                        yield return result;
                    foobar1();
                }
        while (condition)
            foreach (var foo in blah)
                foreach (var result in MyRecursiveYielder(argh)))
                {
                    if (condition2)
                        foreach (var result in MyRecursiveYielder(almostThere)))
                            yield return result;
                    foobar2();
                }
    }
}
4

2 回答 2

1

yield 完成的工作接近于协同程序。您应该能够移植到支持这些的语言。不幸的是,很少有语言可以做到。我相信艾达有他们。

下一步是纤维。Win32 API 暴露了纤程,因此对于 C++ 来说,这可能是一种选择。我认为不适用于Java。

所以,简短的回答:调查你的目标平台的协程或纤程的可用性。

于 2012-10-22T09:51:37.610 回答
0

我想我找到了一个解决方案:我可以在大多数情况下使用 LINQ。这样我就不需要yield在前几个案例中做任何事情,因为这些案例不是有状态的。

有状态的收益——即最后一个——是问题所在——但在睡了之后,我意识到我的“有状态”yield代码基本上只是树搜索(准确地说是广度优先搜索)。基本上喜欢这段代码。

所以我可以简单地创建我自己的IEnumerable<T>执行广度优先搜索的类——即,给定一个传递函数(T parenet) => (IEnumerable<T> children),它会一个接一个地输出孩子,并继续搜索,直到一个都没有。

如果这样行得通,那将摆脱所有yields,同时保持代码结构基本相同——使其更具可读性和更容易移植。

于 2012-10-22T17:27:44.333 回答