Path: csiph.com!usenet.pasdenom.info!nntpfeed.proxad.net!proxad.net!feeder1-2.proxad.net!news.tele.dk!news.tele.dk!small.news.tele.dk!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.007 X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'else:': 0.03; 'discard': 0.05; 'cc:addr:python-list': 0.09; '(same': 0.09; 'part,': 0.09; 'python': 0.10; 'assume': 0.11; '"this': 0.13; 'index': 0.13; 'stack': 0.13; 'def': 0.13; 'missed': 0.15; '*before*': 0.16; 'forking': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'iteration.': 0.16; 'pivot': 0.16; 'wrote:': 0.16; 'element': 0.18; 'tree': 0.18; '2015': 0.20; 'cc:2**0': 0.20; 'cc:addr:python.org': 0.20; 'function,': 0.22; 'wrote': 0.23; 'second': 0.24; 'header:In-Reply-To:1': 0.24; 'paul': 0.24; 'sort': 0.25; "i've": 0.25; "doesn't": 0.26; 'example': 0.26; 'message-id:@mail.gmail.com': 0.27; '14,': 0.27; 'start,': 0.27; 'function': 0.28; 'idea': 0.28; 'looks': 0.29; 'depth': 0.29; 'tail': 0.29; 'array': 0.29; 'subject:/': 0.30; 'work.': 0.30; 'code': 0.30; 'branch': 0.30; 'call.': 0.30; "can't": 0.32; 'call,': 0.33; 'optimize': 0.33; 'tue,': 0.34; 'received:google.com': 0.35; 'could': 0.35; 'step': 0.36; 'but': 0.36; 'instead': 0.36; 'possible': 0.36; 'smaller': 0.36; 'totally': 0.36; 'pm,': 0.36; 'subject:: ': 0.37; 'two': 0.37; 'turn': 0.37; 'say': 0.37; 'doing': 0.38; 'itself': 0.38; 'someone': 0.38; 'means': 0.39; 'does': 0.39; 'where': 0.40; 'still': 0.40; 'space': 0.40; 'some': 0.40; 'claim': 0.61; 'side': 0.62; 'yes': 0.62; 'course': 0.62; 'is.': 0.63; 'more': 0.63; 'potentially': 0.67; 'levels': 0.70; 'jul': 0.72; 'prime': 0.72; 'sounds': 0.76; '(also,': 0.84; 'chrisa': 0.84; 'lacks': 0.84; 'recursion,': 0.84; '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=NEuMbyfCfC8EFwK5AqeCFQ1eQuKk1/hYji/7YEe4CDY=; b=QmGhZ4Xs9R8rjCDukVLne9YISWxOtrPDVW7Fb3jbRjk6utUDlutrbQe9FrZ6JzrQdP cb+EDoySOA0YBA0oB+pQM7uGe3jIOdtWYcLnDIUKO1Opd0w6kV+8eMAeRBAXICdGnj/h xtTU/eH9lppW7JEfysoA3Dppa1kt3pLpHHag1yNo8rntVZ2M07PVsC3q2T7qPTnjEy1T zHvztRpo7Tjr3dfjKBQ8iVBO0RGASseWn23ZPxNhRkakYohDP3DhlwHIihRR3PSuIpsO kNadMge/CZrKTbKnaD2msizo4hfHp/sDVsRBCWQrUqfDLPPqDQ0iguQTXEG78izMtqmO 2Rmg== MIME-Version: 1.0 X-Received: by 10.50.29.75 with SMTP id i11mr16560518igh.50.1436851542044; Mon, 13 Jul 2015 22:25:42 -0700 (PDT) In-Reply-To: <87fv4r1fre.fsf@jester.gateway.sonic.net> References: <55A3A853.4040006@rece.vub.ac.be> <55A3C366.6060602@rece.vub.ac.be> <87fv4r1fre.fsf@jester.gateway.sonic.net> Date: Tue, 14 Jul 2015 15:25:41 +1000 Subject: Re: Possibly Pythonic Tail Call Optimization (TCO/TRE) From: Chris Angelico Cc: "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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 44 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1436851550 news.xs4all.nl 2825 [2001:888:2000:d::a6]:45877 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:93782 On Tue, Jul 14, 2015 at 3:15 PM, Paul Rubin wrote: > It's difficult given how subjective the concept of warping is. What's > straightforward to someone else sounds likely to look warped to you and > vice versa. But how does this look: > > def quicksort(array, start, end): > midp = partition(array, start, end) > if midp <= (start+end)//2: > quicksort(array, start, midp) > quicksort(array, midp+1, end) > else: > quicksort(array, midp+1, end) > quicksort(array, start, midp) > > I assume you know how quicksort and its partition step work. The idea > is you partition the array around the pivot element (midp is the index > of that element), then recursively sort the two partitions, doing the > smaller partition as a recursive call and the larger one as a tail call, > so that you use O(log n) stack depth instead of potentially O(n). > > So the idea is that the second quicksort call in each branch of the if > is a tail call. Yes you could code that as a loop but from my > perspective the way I wrote it above looks more natural. > > Of course it's also possible that I've totally derped this and the > example is no good for some reason I've missed so far ;-). That's a prime example of recursion... but not of recursion that can be tail-call optimized into iteration. It's an example of forking recursion, where one call can result in multiple calls (same with tree traversal); it calls itself to sort the first part and the last part, and while you might be able to turn the second call into a goto, you still need stack space to maintain the first call. The claim that TCO means you don't need stack space for all those levels of recursion doesn't work if you still need stack space for all those levels of recursion *before* you get to the tail call. (Also, side point: Python can't actually optimize the above function, because it actually means "call quicksort, then discard its return value and return None". A true tail call has to return the result of the recursive call, and Python lacks a way to say "this function will always return None". But that's trivial.) ChrisA