Live data from Hacker News

Tail recursion in Python

chrispenner.ca

81–87 of 87 posts

Re: Tail recursion in Python

#81
post #73

Tail recursion is a programming idea left over from the LISP era. It's from when iteration constructs were "while" and "for", and there were no "do this to all that stuff" primitives. Python doesn't really need it.

Tail recursion is unrelated to WHILE and FOR.

Scheme also did not just introduce tail recursion, but full tail call optimization.

Python sure does not need it, it already has a more complex iteration stuff like generators.

Re: Tail recursion in Python

#82
post #74

Earlier quoted context omitted.

Tail calls aren't always just used for some simple iteration. For example, you could have several mutually recursive functions calling each other in tail position. If you wanted to turn that into a loop, you'd have to roll all those functions into a single loop body, which would be made even less elegant due to the lack of goto statement. (TCO essentially turns a call into a goto whenever possible.)

Lots of languages can express it better though - even without gotos. For example in python you can do: while some_condition: x = one_generator(y) y = other_generator(x) where the generators yield values. No need for goto, no TCO, no magic. Even in languages like C, a nicer way to express it may be via two explicit state machines rather than going full Duff's device at this problem.

Python's generators are more magic. It's similar to some kind of COME FROM mechanism.

Re: Tail recursion in Python

#83
post #82

Earlier quoted context omitted.

Lots of languages can express it better though - even without gotos. For example in python you can do: while some_condition: x = one_generator(y) y = other_generator(x) where the generators yield values. No need for goto, no TCO, no magic. Even in languages like C, a nicer way to express it may be via two explicit state machines rather than going full Duff's device at this problem.

Python's generators are more magic. It's similar to some kind of COME FROM mechanism.

Weird comparison. Come from has no indication on the other side that it will happen. Generators are pretty explicit with yield. On the calling side they can be explicit with a next() call.

Re: Tail recursion in Python

#84
post #82

Earlier quoted context omitted.

Python's generators are more magic. It's similar to some kind of COME FROM mechanism.

Weird comparison. Come from has no indication on the other side that it will happen. Generators are pretty explicit with yield. On the calling side they can be explicit with a next() call.

A generator may have multiple yields, if you call next(), then it comes from that call to the last yield call - based on the current execution context. The yield waits that the execution comes back to it.

The idea of function calls is much simpler - no yield magic necessary.

Re: Tail recursion in Python

#85
post #24

Your code is still allocating a new stack frame anyway. So no optimization is happening. You are simply avoiding a stack overflow which is not the purpose of tail-call optimization. I'm not sure if there is any advantage when language/compiler does not provide a proper tail recursive optimization.

It's a gross exaggeration to say there's no advantage. Who decided that stack frame re-use is "the purpose" of tail-call optimization, while not blowing the stack is not? It seems to me that being able to run the function at all is more important than whether it runs quickly.

Re: Tail recursion in Python

#86
This article and the other comments here are interesting, but some are trying to be a bit too clever. The original article isn't too bad, but one of the other comments suggests re-writing the contents of the function at run time, which I really don't think is a practical suggestion (think about debugging such a thing).

If I wanted to do this in practice, I'd just write the trampoline out explicitly, unless I wanted to do it a huge number of times. Doing it this way only takes a couple of extra lines of code but I think that's worth it for the improvement in explicitness, which is a big help for future maintainers (possibly me!).

    from functools import partial

    def _tail_factorial(n, accumulator):
        if n == 0: 
            return accumulator
        else: 
            return partial(_tail_factorial, n - 1, accumulator * n)

    def factorial(n):
        result = partial(_tail_factorial, n, 1)
        while isinstance(result, partial):
            result = result()
        return result

Re: Tail recursion in Python

#87
post #82

Earlier quoted context omitted.

Lots of languages can express it better though - even without gotos. For example in python you can do: while some_condition: x = one_generator(y) y = other_generator(x) where the generators yield values. No need for goto, no TCO, no magic. Even in languages like C, a nicer way to express it may be via two explicit state machines rather than going full Duff's device at this problem.

Python's generators are more magic. It's similar to some kind of COME FROM mechanism.

[deleted]
Post reply on HN