|
Re: Closures
|
Posted: Aug 25, 2005 10:08 AM
|
|
This is a subtle issue. Here is a post I made somewhere else recently that explains the difference:
Anyone interested in this recipe might also like to read a recent book, "Hackers and Painters: Big Ideas from the Computer Age", by Paul Graham (2004).
Though the book is mostly a non-technical discussion of programming principles and practices (generally lionizing Lisp) there is an appendix (pp. 195-99) which compares the __call__ version above to even simpler solutions in other languages.
Though his example is just a generated function with maintained state, rather than a "generator" (ie a function with a "yield" call), it explains exactly why some people appreciate other, more powerful languages.
I disagree with him: The Python example is only slightly more complicated, and it is vastly easier for a non-expert user to comprehend. The implicitly lexical variables do not exactly aid readability.
However, Graham is not unkind to Python, and this book is definitely worth reading for anyone with an interest in the utility of programming languages.
I'm pointing that out because this recipe has caused some big ideas to gel in my mind. After studying this complicated recipe, I suddenly "get" what Python is doing with functions. Tes, the version in the comment is definitely the way I would code it in practice, but I'm glad to see the complex one.
In case you don't have the book, here are his examples. Python first:
class foo: def __init__(self, n): self.n = n def __call__(self, i): self.n +=1; return self.n
Obviously, this could yield self.n instead.
The Java solution is a pain, but in Javascript:
function foo(n) { return function(i) { return n += 1 }}
Smalltalk has strange syntax, but at least has the transparency of the Python version:
foo: n |s| s := n. ^[:i| s := s+i. ]
Perl has an implicit return statement:
sub foo { my ($n) = @_; sub {$n += shift} }
Ruby is the clearest, but with strange delimiters:
def foo (n) lambda {|i| n += i} end
Lisp is easily the least cluttered:
(defun foo(n) (lambda (i) (incf n i)))
The author also lists 2 other Python solutions which work, and 2 which do not work:
def foo(n): class accumulator: def __init__(self, s): self.s = s def inc(self, i): self.s += i return self.s return acc(n).inc
# and
def foo(n): s = [n] # The list holds a copy of n def bar(i): s[0] += i return s[0] return bar
And these 2 do *not* work:
def foo(n): return lambda i: return n += 1
# nor
def foo(n): lambda i: n += 1
The author guesses that Python will one day allow something like these, but only the Python class-based version allows easy access to n. So in fact, what to some is a flaw in Python can be a feature to others.
I hope somebody learns as much from these examples as I have. Functional programming suddenly makes much more sense to me.
|
|