
[Tim]
So what would this look like in Continuation Python?
[Sam]
Here's my first hack at it. Most likely wrong. It is REALLY HARD to do this without having the feature to play with.
[Skip]
The thought that it's unlikely one could arrive at a reasonable approximation of a correct solution for such a small problem without the ability to "play with" it is sort of scary.
Yes it is. But while the problem is small, it's not easy, and only the Icon solution wrote itself (not a surprise -- Icon was designed for expressing this kind of algorithm, and the entire language is actually warped towards it). My first stab at the Python stack-fiddling solution had bugs too, but I conveniently didn't post that <wink>. After studying Sam's code, I expect it *would* work as written, so it's a decent bet that it's a reasonable approximation to a correct solution as-is. A different Python approach using threads can be built using Demo/threads/Generator.py from the source distribution. To make that a fair comparison, I would have to post the supporting machinery from Generator.py too -- and we can ask Guido whether Generator.py worked right the first time he tried it <wink>. The continuation solution is subtle, requiring real expertise; but the threads solution doesn't fare any better on that count (building the support machinery with threads is also a baffler if you don't have thread expertise). If we threw Python metaclasses into the pot too, they'd be a third kind of nightmare for the non-expert. So, if you're faced with this kind of task, there's simply no easy way to get it done. Thread- and (it appears) continuation- based machinery can be crafted once by an expert, then packaged into an easy-to-use protocol for non-experts. All in all, I view continuations as a feature most people should actively avoid! I think it has that status in Scheme too (e.g., the famed Schemer's SICP textbook doesn't even mention call/cc). Its real value (if any <wink>) is as a Big Invisible Hammer for certified wizards. Where call_cc leaks into the user's view of the world I'd try to hide it; e.g., where Sam has def walk (self, x): if type(x) == type([]): for item in x: self.walk (item) else: self.item = x # call self.suspend() with a continuation # that will continue walking the tree call_cc (self.suspend) I'd do def walk(self, x): if type(x) == type([]): for item in x: self.walk(item) else: self.put(x) where "put" is inherited from the base class (part of the protocol) and hides the call_cc business. Do enough of this, and we'll rediscover why Scheme demands that tail calls not push a new stack frame <0.9 wink>. the-tradeoffs-are-murky-ly y'rs - tim