The easiest way to get rid of the "crop" in (by converting to a state machine) a recursive generator method?

I have a nice, elegant (IMO) piece of code that I wrote that I want to port to other languages ​​like C ++, Java, etc.

The problem I am facing is twofold:

  • The code uses yield
  • The code is very recursive

Getting rid of yield manually is possible, but very tiring - the process is very mechanical and, obviously, automatically.
At the same time, the state machine that the C # compiler translates into this is very ugly - it is practically not applicable for porting. (I tried to decompile it, it's just unreadable.)

I am wondering if I have any other options besides just spending days on this to get rid of yield manually?
Or is there some kind of tool that can convert yield blocks to the (readable) state of the machine, which I can then transfer as normal code?


In case you are interested in what I mean by the term β€œvery recursive” - the code below is basically the code structure (the actual thing is only ~ 66 lines, this is not a very long function):

 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
source share
2 answers

I think I found a solution: I can use LINQ, for the most part. Thus, I would not need to yield anything in the first few cases, because these cases have no state.

The result of the state - that is, the last one - is the problem - but after sleeping on it I realized that my "stateful" yield code is basically just a tree search (width search, or rather). Basically, like this code.

So I could just create my own IEnumerable<T> class, which does a breadth-first search, i.e. given the transfer function (T parenet) => (IEnumerable<T> children) , it will output the children one by one and continue searching until it is to the left.

If this works, it will save you all yield s, while keeping the code structure essentially the same, which makes it more readable and easy to port.

0
source

Achieving results is close to working together. You should be able to port them to a language that supports them. Unfortunately, very few languages. I think Ada has them.

The next step is the fibers. The Win32 API provides fibers, so for C ++ this might be an option. Not for Java, I think.

So, the short answer is: research for related software or fibers for your target platforms.

+1
source

Source: https://habr.com/ru/post/1441242/


All Articles