Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #95024
| 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 | Next — Previous in thread | Next in thread | Find similar | Unroll 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