Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #55382

Re: Tail recursion to while iteration in 2 easy steps

Path csiph.com!usenet.pasdenom.info!aioe.org!news.stack.nl!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail
Return-Path <python-python-list@m.gmane.org>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.000
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'python,': 0.02; 'programmer': 0.03; 'operator': 0.03; 'languages.': 0.04; 'syntax': 0.04; 'assignment': 0.07; 'compiler': 0.07; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'rewrite': 0.09; 'semantic': 0.09; 'subject:while': 0.09; 'python': 0.11; 'def': 0.12; 'jan': 0.12; 'assume': 0.14; 'clauses': 0.16; 'expression.': 0.16; 'iterable': 0.16; 'iteration': 0.16; 'iterator': 0.16; 'loops': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'reedy': 0.16; 'subject:recursion': 0.16; 'language': 0.16; 'wrote:': 0.18; 'code.': 0.18; "python's": 0.19; 'replacing': 0.19; 'starts': 0.20; 'written': 0.21; 'input': 0.22; 'programming': 0.22; 'saying': 0.22; 'header:User-Agent:1': 0.23; 'instead.': 0.24; '(or': 0.24; 'source': 0.25; 'post': 0.26; 'header:X-Complaints- To:1': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'am,': 0.29; 'points': 0.29; 'raise': 0.29; 'converting': 0.30; 'matching': 0.30; 'that.': 0.31; '(possibly': 0.31; 'assumes': 0.31; 'encouraged': 0.31; 'implied': 0.31; 'ones.': 0.31; 'styles': 0.31; 'style': 0.33; 'convert': 0.35; 'late': 0.35; 'but': 0.35; 'version': 0.36; 'really': 0.36; 'done': 0.36; 'should': 0.36; 'two': 0.37; 'list': 0.37; 'expressed': 0.37; 'auto': 0.38; 'to:addr:python-list': 0.38; 'rather': 0.38; 'does': 0.39; 'functional': 0.39; 'to:addr:python.org': 0.39; 'received:org': 0.40; 'easy': 0.60; 'is.': 0.60; 'conversion': 0.61; 'length': 0.61; 'received:173': 0.61; 'different': 0.65; 'here': 0.66; 'determine': 0.67; 'integrated': 0.69; 'secret': 0.74; 'collection.': 0.84; 'iterative': 0.84; 'n):': 0.84; 'received:fios.verizon.net': 0.84; 'recursion,': 0.84; 'recursive.': 0.84; '2013,': 0.91; 'apparent': 0.91; 'steps.': 0.91; 'directly.': 0.95
X-Injected-Via-Gmane http://gmane.org/
To python-list@python.org
From Terry Reedy <tjreedy@udel.edu>
Subject Re: Tail recursion to while iteration in 2 easy steps
Date Wed, 02 Oct 2013 17:33:27 -0400
References <l2feu0$n61$1@ger.gmane.org> <1380717085.6985.29063445.6AD889D5@webmail.messagingengine.com>
Mime-Version 1.0
Content-Type text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding 7bit
X-Gmane-NNTP-Posting-Host pool-173-75-251-66.phlapa.fios.verizon.net
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.0
In-Reply-To <1380717085.6985.29063445.6AD889D5@webmail.messagingengine.com>
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <https://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <https://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.652.1380749629.18130.python-list@python.org> (permalink)
Lines 68
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1380749629 news.xs4all.nl 15888 [2001:888:2000:d::a6]:36882
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:55382

Show key headers only | View raw


On 10/2/2013 8:31 AM, random832@fastmail.us wrote:
> On Tue, Oct 1, 2013, at 17:30, Terry Reedy wrote:
>> Part of the reason that Python does not do tail call optimization is
>> that turning tail recursion into while iteration is almost trivial, once
>> you know the secret of the two easy steps. Here it is.
>
> That should be a reason it _does_ do it - saying people should rewrite
> their functions with loops means declaring that Python is not really a
> multi-paradigm programming language but rather rejects functional
> programming styles in favor of imperative ones.

It is true that Python does not encourage the particular functional 
style that is encouraged by auto optimization of tail recursion. A 
different functional style would often use reduce (or fold) instead.

Some other points I left out in a post of medium length yet brief for 
the topic.

1. If one starts with body recursion, as is typical, one must consider 
commutativity (possibly associativity) of the 'inner' operator in any 
conversion.

2. Instead of converting to tail recursion, one might convert to while 
iteration directly.

3. One often 'polishes' the while form in a way that cannot be done 
automatically.

4. While loops are actually rare in idiomatic Python code. In Python, 
for loops are the standard way to linearly process a collection. The 
final version I gave for a factorial while loop,

def fact_while(n):
   if n < 0 or n != int(n):
     raise ValueError('fact input {} is not a count'.format(n))
   fac = 1
   while n > 1:
     fac *= n
     n -= 1
   return fac

should better be written with a for loop:

def fact_for(n):
   if n < 0 or n != int(n):
     raise ValueError('fact input {} is not a count'.format(n))
   fac = 1:
   for i in range(2, n):
     fac *= n

When the input to a function is an iterable instead of n, the iterable 
should be part of the for loop source expression. For loops are 
integrated with Python's iterator protocol in much the same way that 
recursion is integrated with list first:rest pattern matching in some 
functional languages. It is true that Python encourages the use of for 
loops and for clauses in comprehensions (a functional construct).

5. Conversion of apparent recursion to iteration assumes that the 
function really is intended to be recursive.  This assumption is the 
basis for replacing the recursive call with assignment and an implied 
internal goto. The programmer can determine that this semantic change is 
correct; the compiler should not assume that. (Because of Python's late 
name-binding semantics, recursive *intent* is better expressed in Python 
with iterative syntax than function call syntax. )

-- 
Terry Jan Reedy

Back to comp.lang.python | Previous | NextNext in thread | Find similar | Unroll thread


Thread

Re: Tail recursion to while iteration in 2 easy steps Terry Reedy <tjreedy@udel.edu> - 2013-10-02 17:33 -0400
  Re: Tail recursion to while iteration in 2 easy steps 88888 Dihedral <dihedral88888@gmail.com> - 2013-10-04 02:13 -0700

csiph-web