<div dir="ltr">Hi there,<br><br>First, please forgive me if this is the wrong venue to be suggesting this idea-- I'm just following the <a href="https://www.python.org/dev/peps/pep-0001/#pep-workflow">PEP workflow page</a>.<br><br>I've recently been playing around with Clojure, and I really like the way they've overcome the JVM not supporting TRE. The way Clojure solves this problem is to have a built in "recur" function that signals to the Clojure compiler to convert the code to a loop in the JVM. In python we could do something similar by having a <b>recur(*args, **kwargs)</b> function that removes its parent from the stack and then runs the parent function again with the given arguments. It would look something like this:<br><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><table class="" style="border-collapse:collapse;border-spacing:0px;color:rgb(51,51,51);font-family:Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif,'Segoe UI Emoji','Segoe UI Symbol';font-size:13px;line-height:18.2000007629395px"><tbody><tr><td id="LC9" class="" style="padding:0px 10px;vertical-align:top;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;overflow:visible;word-wrap:normal"><span class="" style="color:rgb(24,54,145)">def factorial(n, acc=1):</span></td></tr></tbody></table></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;line-height:18.2000007629395px">if n == 0:</span></blockquote></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;line-height:18.2000007629395px">return acc</span></div></blockquote></blockquote></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;line-height:18.2000007629395px">else:</span></div></div></blockquote></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:18.2000007629395px;white-space:pre">return recur(n-1, acc=(acc*n)) #signals to the interpreter to trigger TRE</span></div></div><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:18.2000007629395px;white-space:pre"><br></span></div></blockquote></blockquote></blockquote><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><table class="" style="border-collapse:collapse;border-spacing:0px;color:rgb(51,51,51);font-family:Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif,'Segoe UI Emoji','Segoe UI Symbol';font-size:13px;line-height:18.2000007629395px"></table></blockquote></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;line-height:18.2000007629395px"><br></span></div><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;line-height:18.2000007629395px"># Doesn't overflow the stack!</span></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><table class="" style="border-collapse:collapse;border-spacing:0px;color:rgb(51,51,51);font-family:Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif,'Segoe UI Emoji','Segoe UI Symbol';font-size:13px;line-height:18.2000007629395px"></table></blockquote></div><div><span style="color:rgb(24,54,145);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;line-height:18.2000007629395px">factorial(30000)</span></div></blockquote><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><br><table class="" style="border-collapse:collapse;border-spacing:0px;color:rgb(51,51,51);font-family:Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif,'Segoe UI Emoji','Segoe UI Symbol';font-size:13px;line-height:18.2000007629395px"><tbody><tr><td id="L14" class="" style="padding:0px 10px;width:50px;min-width:50px;white-space:nowrap;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:18px;color:rgba(0,0,0,0.298039);vertical-align:top;text-align:right;border-style:solid;border-color:rgb(238,238,238);border-width:0px 1px 0px 0px"></td><td id="LC14" class="" style="padding:0px 10px;vertical-align:top;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;white-space:pre;overflow:visible;word-wrap:normal"><span class="" style="color:rgb(24,54,145)"></span></td></tr></tbody></table></blockquote>I've also created a <a href="https://github.com/blackfedora/recur.py/blob/master/recur.py">plugin</a> that mocks this behavior using the try/except looping method that <a href="http://code.activestate.com/recipes/474088/">others</a> have utilized to implement TCO into python. Of course, my plugin still requires a decorator and the overhead of transmitting information through an exception. Implementing recur with interpreter support should lead to much better performance. <br><br>I've read <a href="http://neopythonic.blogspot.co.uk/2009/04/tail-recursion-elimination.html">Guido's reasoning against dynamic TCO</a>, but I believe many of his concerns can be boiled down to "I don't want the interpreter doing things the user didn't expect, and I just don't think this is important enough to affect everyone's experience". This recur approach solves that by giving functional python users the ability to explicitly tell the interpreter what they want without changing how other users interact with the interpreter. Guido also notes that TRE removes removes stack trace data. While a more subtle garbage collection scheme would help alleviate this problem, there's really no avoiding this. My only defense is that this solution is at least explicit, so users should know that they're implementing code that might produce a completely unhelpful stack trace.<br><font color="#333333"><span style="line-height:17.6800003051758px"><font face="arial, helvetica, sans-serif"><br>Thank you for your time and consideration; I hope this was at least interesting!<br><br>All the best,<br>Ian Burnette</font><br></span></font><div><br></div><div><div><div class="gmail_signature"><div dir="ltr"><b><font size="4" face="garamond, serif">Ian Burnette</font></b><div><font face="garamond, serif">Python/Django Developer</font></div><div><font face="garamond, serif">Cox Media Group</font></div><div><font face="garamond, serif">P: <span title="Call with Google Voice"><span id="gc-number-0" class="" title="Call with Google Voice"><span id="gc-number-1" class="" title="Call with Google Voice">843.478.5026</span></span></span></font></div><div><br></div></div></div></div>
</div></div></div>