However, all the major implementations (SBCL, Clozure CL, Franz Allegro, LispWorks, CMUCL, and I think even ECL) do tail-call elimination on local calls. (A local call is a call to a function whose definition is lexically visible, such as the calls to 'helper' in your example.) The document says that TCE depends on optimization settings, but for local calls, I'm not sure even that is true. Anyway, the practical upshot, in my experience, is that there's no reason not to write loops recursively using LABELS when that is the most elegant expression of the particular loop in question.
(There was once a major implementation that never did TCE -- Genera -- but even for die-hard Lisp Machine lovers like myself, it has long since been relegated to a historical curiosity.)
This version quickly dumped Heap Exhaustion. The LABELS version does not, and can handle summation over lists much faster as well.
What does this mean? TCE only applies applies to local calls, therefore we should never write a "raw" recursive function? (which is a tad more elegant, imo). I haven't delved into TCOs deep enough to understand, but I had hoped that a smart compiler would be able to optimize the latter?
However, all the major implementations (SBCL, Clozure CL, Franz Allegro, LispWorks, CMUCL, and I think even ECL) do tail-call elimination on local calls. (A local call is a call to a function whose definition is lexically visible, such as the calls to 'helper' in your example.) The document says that TCE depends on optimization settings, but for local calls, I'm not sure even that is true. Anyway, the practical upshot, in my experience, is that there's no reason not to write loops recursively using LABELS when that is the most elegant expression of the particular loop in question.
(There was once a major implementation that never did TCE -- Genera -- but even for die-hard Lisp Machine lovers like myself, it has long since been relegated to a historical curiosity.)