Самый простой способ избавиться от "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)
, он будет выводить дочерние элементы один за другим и продолжать поиск, пока не останется ни одного.
Если это сработает, это избавит от всех yield
s, сохраняя при этом структуру кода, по сути, одинаковой - делая ее намного более читабельной и удобной для переноса.
То, что приносит доход, близко к совместным действиям. Вы должны быть в состоянии портировать на язык, который поддерживает их. К сожалению, очень мало языков. Я верю, что у Ады они есть.
Следующий шаг - волокна. Win32 API предоставляет волокна, поэтому для C++ это может быть вариантом. Не для Java, я думаю.
Итак, короткий ответ: исследуйте наличие сопрограмм или оптоволокна для ваших целевых платформ.