[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Accumulator



Avi Bryant wrote:
> 
>...
> 
> Just to clarify - what I think you mean is that anything that can be done
> with *Python's limited form of lambda* can be done without it, since inner
> functions have the same restrictions lambda does.

Inner functions have less restrictions than lambda, but the particular
restriction about overwriting variables from outer scopes is still in
effect. I still maintain that this encourages a better (OO, in an OO
programming language) style of programming. It seems strange to me that
it is hard to get people to agree that Python's choice might just be
better for Python programmers.

>...
> Paul, I'm curious - what is the idiomatic Python equivalent to
> continuation-passing-style?  I honestly can't imagine a way to write code
> in CPS not using lambda (that is, a full, "context-mutating" lambda)
> without it being horribly ugly to the point of unreadability.  Even given
> that Python doesn't have full first class continuations (does stackless?
> or are they just co-routines?), can it reasonably simulate them?

Stackless has full continuations. Even so, I cannot recall ever seeing
anything resembling CPS in Python code (very little Python code depends
on Stackless). The most serious limitation would be the lack of tail
recursion.

But anyhow, *any closure can be turned into an object*. And to a Python
programmer (or Java programmer, or VB programmer, or C++ programmer), in
virtually every case, the result will be more, not less, readable.
Insofar as there is a near mechanical transformation from closure-style
to object-style, I find it surprising that the belief persists that this
is a source of power. 

OTOH, tail recursion or true continuations are real language features
that have no Python equivalent. That's a different situation than
mutable continuations.

> If it can't, and I have a hard time seeing how it could, then that is a
> huge blow to its power and usefulness for what I do, which is build web
> applications.  You will argue that thousands upon thousands of people
> write web applications in Python, or other languages without
> continuations, which is true - that doesn't stop me from being able to
> consistently underbid them because I use more powerful tools.

We'll have to agree to disagree. You will say that you really are more
productive and if I only understood how you use CPS I would see that.
I'll say that you really are not more productive and if you only
understood how to use Python objects you would see that. You've got
anecdotes of Lisp web hackers getting rich by beating competitors. I've
got anecdotes of Python web hackers getting rich by beating competitors.

> (BTW, I looked at
> http://www.ps.uni-sb.de/~duchier/python/continuations.html, which
> discusses CPS in Python, but the example it gives happens not to do any
> mutation, so it gets away with using Python's lambda - and even then,
> states "What becomes evident in the above is that Python's lack of real
> closures makes it a bit painful to write what in a functional language is
> truly succinct and elegant.").

That page is out of date. The example he gives would not require hacks
today. But even so, the CPS code is gross *because it uses CPS* (as
opposed to because it uses CPS in Python). I would strongly criticize
any programmer who checked that into a code base. If you show me some
CPS code that is easier to read than the equivalent object-based code
then I might be more persuaded.

I'll append both versions.

 Paul Prescod

# CPS way 
class IsDivisible:
  def __init__(self, divisor):
    self.divisor = divisor

  def search(self,info,yes,no):
    if self.check(info):
      return yes(info,no)
    else:
      return no()

  def check(self, info):
    return info%self.divisor==0

class Disjunction:
  def __init__(self,foo1,foo2):
    self.one = foo1
    self.two = foo2
  def search(self,info,yes,no):
    return self.one.search(
      info, yes,
      lambda: self.two.search(info,yes,no))

a = IsDivisible(7)
b = IsDivisible(10)
baz = Disjunction(a, b)

def yes(*args):
    print "yes", args
def no(*args):
    print "no", args

baz.search(20, yes, no) # prints yes
baz.search(14, yes, no) # prints yes
baz.search(5, yes, no)  # prints no

## Standard way
class IsDivisible:
    def __init__(self, divisor):
        self.divisor = divisor

    def search(self, info):
        return self.check(info)

    def check(self, info):
        return info%self.divisor==0

class Disjunction:
    def __init__(self, test1, test2):
        self.test1 = test1
        self.test2 = test2
    def search(self, info):
        return self.test1.search(info) or self.test2.search(info)

a = IsDivisible(7)
b = IsDivisible(10)

d = Disjunction(a,b)
print d.search(10)
print d.search(7)
print d.search(3)