Remix.run Logo
Recursive Problems Benefit from Recursive Solutions(jnkr.tech)
27 points by luispa 3 days ago | 9 comments
twic 5 minutes ago | parent | next [-]

> This solution looks extremely similar to the previous one, which is a good thing. Our requirements have experienced a small change (reversing the traversal order) and our solution has responded with a small modification.

Now do breadth-first traversal. With the iterative approach, you just replace the stack with a queue. With the recursive approach, you have to make radical changes. You can make either approach look natural and elegant if you pick the right example.

twic 13 minutes ago | parent | prev | next [-]

> It seems to be common knowledge that any recursive function can be transformed into an iterative function.

Huh. Where i work, the main problem is that everyone is hell-bent on transforming every iterative function into a recursive function. If i had a pound for every recursive function called "loop" in the codebase, i could retire.

jonathanlydall an hour ago | parent | prev | next [-]

It depends on whether the limited call stack capacity will be an issue for the particular problem you’re solving.

I’m presently working on a problem which uses traversal of TypeScript file syntax trees.

I can reasonably assume that we will never get a file with a deep enough syntax tree which would cause a stack overflow.

A manually managed stack might seem safer, but as pointed out by this article the code would be more complicated and, in my case, for no good reason.

layer8 33 minutes ago | parent [-]

In practice, a heap-based manual stack can be as unsafe with unbounded input as using the native call stack (considering typical OOM behavior). If you have untrusted input, you might want to limit the stack depth in either case. And it’s not difficult to add a recursion counter to recursive calls. So I don’t think it’s an inherently distinguishing feature between the two approaches.

Personally I tend to find the iterative approach easier to follow when no actual stack is needed, i.e. in the tail-call case.

swiftcoder 3 hours ago | parent | prev [-]

This has always felt like the kind of thing we could be building compilers to solve. Recursive -> explicit stack is a very mechanical conversion, why can't we write a compiler transform pass that does that rewrite any time it detects a high potential for stack overflow?

derriz an hour ago | parent | next [-]

It’s called TCO - tail call optimization - and gcc and llvm are supposed to implement it although tail recursive style code is probably uncommon in C or C++. Outside of that it’s common in functional languages where recursive functions are obviously idiomatic and so it has more potential to provide performance benefit.

It’s not a purely local optimization - affecting the call structure so debugging is a pain point. Which is probably why most imperative language compilers don’t bother given the lack of utility for the vast majority of code bases.

It feels like something that would need to be specified at the language spec or semantics level to make it useful rather than just making it optional for the compiler - otherwise the developer is probably just going to do the transform manually - to be safe - if stack explosion was a possibility if the compiler decided on a whim to not perform TCO.

afiori 33 minutes ago | parent [-]

Just like many languages have annotations for inlining functions they could have annotations for tco. From an usability pov i would like annotations for must, must not, should, and should not. Where the "must" versions error if the compiler can't do the optimization

Epa095 an hour ago | parent | prev | next [-]

Yeah, tail call elimination, is definitely doable.

Python famously does not have it because "Language inventor Guido van Rossum contended that stack traces are altered by tail-call elimination making debugging harder, and preferred that programmers use explicit iteration instead". https://en.wikipedia.org/wiki/Tail_call

Jaxan 2 hours ago | parent | prev [-]

Many compilers do change a recursion into a loop, avoiding the stack altogether!