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


Groups > comp.lang.python > #95024

Re: Is this an example of tail recursion?

Path csiph.com!goblin2!goblin.stu.neva.ru!newsfeed.xs4all.nl!newsfeed7.news.xs4all.nl!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail
Return-Path <rosuav@gmail.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.004
X-Spam-Evidence '*H*': 0.99; '*S*': 0.00; 'else:': 0.03; 'method,': 0.07; 'cc:addr:python-list': 0.09; 'implies': 0.09; 'returns,': 0.09; 'rounds': 0.09; 'subclass': 0.09; 'subclasses': 0.09; 'def': 0.13; 'ignore': 0.14; 'argument': 0.15; 'thu,': 0.15; 'value.': 0.15; '"is': 0.16; '1:13': 0.16; 'clear.': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'function).': 0.16; 'helps!': 0.16; 'infinity': 0.16; 'subject:recursion': 0.16; 'sure.': 0.16; 'trap': 0.16; 'value:': 0.16; 'wrote:': 0.16; 'case.': 0.18; '2015': 0.20; 'cc:2**0': 0.20; 'cc:addr:python.org': 0.20; 'aug': 0.20; 'function,': 0.22; 'trying': 0.22; 'am,': 0.23; "python's": 0.23; 'this:': 0.23; 'header:In-Reply-To:1': 0.24; "doesn't": 0.26; '(which': 0.26; 'possibility': 0.27; 'message-id:@mail.gmail.com': 0.27; 'function': 0.28; 'looks': 0.29; 'block,': 0.29; 'dead,': 0.29; 'equally': 0.29; 'fighting': 0.29; 'tail': 0.29; 'convert': 0.29; 'code': 0.30; 'call.': 0.30; 'skip:s 30': 0.31; 'another': 0.32; "can't": 0.32; 'skip:_ 10': 0.32; 'non': 0.32; 'though,': 0.32; 'point': 0.33; 'call,': 0.33; 'effort.': 0.33; 'add': 0.34; 'that,': 0.34; 'received:google.com': 0.35; 'could': 0.35; 'done': 0.35; 'returning': 0.35; 'skip:s 60': 0.35; "isn't": 0.35; 'but': 0.36; 'subject:?': 0.36; 'subject:: ': 0.37; 'skip:s 50': 0.37; 'doing': 0.38; 'version': 0.38; 'skip:s 40': 0.38; 'turned': 0.38; 'someone': 0.38; 'end': 0.39; 'means': 0.39; 'goes': 0.39; 'sure': 0.39; 'where': 0.40; 'still': 0.40; 'your': 0.60; "you'll": 0.61; 'hope': 0.61; 'more': 0.63; 'different': 0.63; 'necessarily': 0.63; 'between': 0.65; 'differences': 0.66; 'here': 0.66; 'worth': 0.67; 'choose': 0.68; 'attacking': 0.84; 'chrisa': 0.84; 'etc,': 0.84; 'recursion,': 0.84; 'recursive.': 0.84; 'ugly,': 0.84; 'subject:this': 0.85; 'absolutely': 0.88; 'to:none': 0.91
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:cc :content-type; bh=PvIfPXAlUkiYxpbPy9wb2UHJnodMzH/QDnGUoVxQjU0=; b=jhSwyUnupe31HQpxlyBqEViKJ2XtL/y/53+GzSjBHr/PcI46ldwftXdxW/fiNMPEis Z8aED5f26t5hoPY9r850Gc754VraAPdV/uPMmjB2mZSVaR3rUJKtxtI9F/OJ/4pNSmeG bPMtB0d1+wr47qu0Evjtc2zbR+2ypSoMJ15ztzSZ5zyMzkQjdQ39P+EXfSFppvTItAZx r+iUQ5fbknl9qDxNGHHZio5GJF/WdJF3g9nx1Z/FSbgaJeT6TtdIuVHLdhlCG88v5cmi QZSdHSWZLr1EFm6NZPU2JXtw4a5/u3rUcBMxQyD9+eJH0i0mvRkq3eLzCFbnzwOpMYvJ 9N8g==
MIME-Version 1.0
X-Received by 10.107.31.134 with SMTP id f128mr10025161iof.19.1438789917513; Wed, 05 Aug 2015 08:51:57 -0700 (PDT)
In-Reply-To <53903f1c-a740-4508-9d24-0b0bec9ad339@googlegroups.com>
References <53903f1c-a740-4508-9d24-0b0bec9ad339@googlegroups.com>
Date Thu, 6 Aug 2015 01:51:57 +1000
Subject Re: Is this an example of tail recursion?
From Chris Angelico <rosuav@gmail.com>
Cc "python-list@python.org" <python-list@python.org>
Content-Type text/plain; charset=UTF-8
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.20+
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.1241.1438789920.3674.python-list@python.org> (permalink)
Lines 125
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1438789920 news.xs4all.nl 2931 [2001:888:2000:d::a6]:49864
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:95024

Show key headers only | View raw


On Thu, Aug 6, 2015 at 1:13 AM,  <jennyfurtado2@gmail.com> wrote:
> I am trying to learn differences between tail recursion and non tail recursion.

Tail recursion is where you do exactly this:

    return some_function(...)

Absolutely nothing is allowed to happen around or after that function,
and that also means you can't do that inside a try/except/finally
block, nor a with block, etc, etc, etc. It has to be nothing more than
a function call, and you return the exact result of that call.

> Is the following recursive code tail recursive?
> If it is not how to convert it to tail recursion?
> If it is how to convert it to non tail recursion?
>
>    def __init__(self):
>        self.dpw = 0

Not tail recursive - not recursive - doesn't call anything. Trivial case. :)

>    def soldiersVsDefenders(self,soldiers,defenders):
>        # soldiers win
>        if defenders <=0:
>           return 0
>        # castle/defenders win
>        if soldiers <= 0:
>           return self.INFINITY

In these cases, equally trivial - not recursive in any form.

>        # do another round of fighting
>        # 1. Soldiers kill as many defenders
>        defendersLeft = defenders - soldiers
>        # 2. defendersLeft kill as many soldiers
>        soldiersLeft = soldiers - defendersLeft

(Interesting that the attacking soldiers get the first strike.)

>        return 1 + self.soldiersVsDefenders(soldiersLeft,defendersLeft)

This is NOT tail recursion, because you add 1 at the end of it. The
way to make it tail recursive would be to add another argument to the
function, which it would keep adding to; whenever it returns, you
would add the accumulator to the return value:

def soldiersVsDefenders(self,soldiers,defenders, accum=0):
    if defenders <= 0:
        return 0 + accum
    if soldiers <= 0:
        return self.INFINITY + accum
    # other code goes here
    return self.soldiersVsDefenders(soldiersLeft,defendersLeft,1+accum)

Now it's tail recursive. If this looks ugly, it's because it is; tail
recursion often isn't worth the effort.

Note that, as far as Python's concerned, this is a tail call, but
isn't necessarily *recursion* (which implies that you somehow know
you're calling the same function). If someone subclasses your code and
overrides this method, your code will call the subclass's version - if
the subclass calls through to super(), you'll end up with mutual
recursion, but still not a simple case of tail recursion. However, you
could choose to ignore this possibility and manually convert this into
iteration:

def soldiersVsDefenders(self,soldiers,defenders):
    rounds = 0
    while soldiers and defenders:
        # do another round of fighting
        # 1. Soldiers kill as many defenders
        defendersLeft = defenders - soldiers
        # 2. defendersLeft kill as many soldiers
        soldiersLeft = soldiers - defendersLeft
        rounds += 1
    if defenders <= 0:
        return rounds
    return self.INFINITY + rounds

How's that look? Better? Worse?

On to the next function.

>    def oneWave(self,soldiers,defenders,castleHits):
>        # castle is dead, let soldiers play against defenders
>        if castleHits <= 0:
>            defendersLeft = defenders - self.dpw
>            return self.soldiersVsDefenders(soldiers,defendersLeft)

This is a tail call. It's not tail *recursion* because you're calling
a completely different function, but you are indeed calling another
function and directly returning its return value.

>        mini = self.INFINITY
>        for i in range(0,soldiers):
>            if i > defenders:
>                 break
>            soldiersLeft = soldiers - (defenders -i)
>            defendersLeft = defenders - i + self.dpw
>            castleHitsLeft = castleHits - (soldiers -i)
>            mini = min(mini,1 + self.oneWave(soldiersLeft,defendersLeft,castleHitsLeft))
>        return mini

Not sure what the point of all this is, but sure. This clearly isn't
tail recursion, though, as it's doing a whole lot of other work after
the recursive call. Having a loop and recursion like this is pretty
scary, but in terms of "is this or isn't this tail recursive", it's
pretty clear.

>    def playGame(self,soldiers,castleHits,defendersPerWave):
>        self.dpw = defendersPerWave
>        numWaves = self.oneWave(soldiers,0,castleHits)
>        if numWaves >= self.INFINITY:
>           return -1
>        else:
>           return numWaves

And this is, again, no tail call. If the trap for INFINITY becoming -1
were inside oneWave(), then this could be turned into a tail call, but
as it is, there's more work to be done after the other function
returns, so it's not a tail call.

Hope that helps!

ChrisA

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


Thread

Is this an example of tail recursion? jennyfurtado2@gmail.com - 2015-08-05 08:13 -0700
  Re: Is this an example of tail recursion? Rustom Mody <rustompmody@gmail.com> - 2015-08-05 08:21 -0700
    Re: Is this an example of tail recursion? jennyfurtado2@gmail.com - 2015-08-05 08:37 -0700
      Re: Is this an example of tail recursion? Chris Angelico <rosuav@gmail.com> - 2015-08-06 01:54 +1000
      Re: Is this an example of tail recursion? Rustom Mody <rustompmody@gmail.com> - 2015-08-05 09:10 -0700
        Re: Is this an example of tail recursion? jennyfurtado2@gmail.com - 2015-08-05 09:15 -0700
        Re: Is this an example of tail recursion? Chris Angelico <rosuav@gmail.com> - 2015-08-06 02:28 +1000
          Re: Is this an example of tail recursion? jennyfurtado2@gmail.com - 2015-08-05 09:41 -0700
            Re: Is this an example of tail recursion? Rustom Mody <rustompmody@gmail.com> - 2015-08-05 09:51 -0700
              Re: Is this an example of tail recursion? Chris Angelico <rosuav@gmail.com> - 2015-08-06 03:10 +1000
  Re: Is this an example of tail recursion? Chris Angelico <rosuav@gmail.com> - 2015-08-06 01:51 +1000
    Re: Is this an example of tail recursion? jenny <jennyfurtado2@gmail.com> - 2015-08-05 08:59 -0700

csiph-web