Самый простой способ избавиться от "yield" в (путем преобразования в конечный автомат) метод рекурсивного генератора?

У меня есть хороший, элегантный (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();
                }
    }
}

2 ответа

Решение

Я думаю, что нашел решение: я могу использовать LINQ, по большей части. Таким образом, мне не нужно yield что-нибудь в первых нескольких случаях, потому что эти случаи не с учетом состояния.

Выход из состояния - то есть последний - это проблема - но, поспав на нем, я понял, что мой "состоящий из состояний" yield код в основном просто поиск по дереву (поиск в ширину, если быть точным). В основном, как этот код.

Так что я мог бы просто сделать свой собственный IEnumerable<T> класс, который выполняет поиск в ширину - т.е., учитывая передаточную функцию (T parenet) => (IEnumerable<T> children), он будет выводить дочерние элементы один за другим и продолжать поиск, пока не останется ни одного.

Если это сработает, это избавит от всех yields, сохраняя при этом структуру кода, по сути, одинаковой - делая ее намного более читабельной и удобной для переноса.

То, что приносит доход, близко к совместным действиям. Вы должны быть в состоянии портировать на язык, который поддерживает их. К сожалению, очень мало языков. Я верю, что у Ады они есть.

Следующий шаг - волокна. Win32 API предоставляет волокна, поэтому для C++ это может быть вариантом. Не для Java, я думаю.

Итак, короткий ответ: исследуйте наличие сопрограмм или оптоволокна для ваших целевых платформ.

Другие вопросы по тегам