On Wed, 16 Mar 2005 00:36:40 +0100, Marcin 'Qrczak' Kowalczyk <[EMAIL PROTECTED]> wrote:
>[EMAIL PROTECTED] (Thomas A. Russ) writes: > >>> >(defun addn (n) >>> > #'(lambda (x) >>> > (+ x n))) >>> >>> The same as >>> def addn(n): >>> def fn(x): >>> return n + x >>> return fn >> >> Is this really equivalent? >> >> What happens if you call addn more than once with different >> parameters. Will you get different functions that you can >> use simultaneously? > >Yes. > >It also behaves correctly when a variable it refers to is later >mutated. > > >BTW, the fact that a closure refers to a variable itself rather to its >current value can be used to check the true attitude of languages with >respect to functional programming, by observing how they understand >their basic loops :-) > >Python loses: > >>>> closures = [] >>>> for i in range(10): >... def add(x): >... return x + i >... closures.append(add) >... >>>> closures[5](1000) >1009 Fire the coach -- the team can do it ;-) One way is with the help of a byte-code-hacking decorator: >>> from ut.presets import presets >>> closures = [] >>> for i in range(10): ... @presets(i=i) ... def add(x): ... return x + i ... closures.append(add) ... >>> closures[5](1000) 1005 >>> import dis >>> dis.dis(closures[5]) 2 0 LOAD_CONST 1 (5) 3 STORE_FAST 1 (i) 4 6 LOAD_FAST 0 (x) 9 LOAD_FAST 1 (i) 12 BINARY_ADD 13 RETURN_VALUE >>> dis.dis(closures[3]) 2 0 LOAD_CONST 1 (3) 3 STORE_FAST 1 (i) 4 6 LOAD_FAST 0 (x) 9 LOAD_FAST 1 (i) 12 BINARY_ADD 13 RETURN_VALUE Of course, if you want to do it without byte code hacking, you can: >>> closures2 = list((lambda i: lambda x: x + i)(i) for i in xrange(10)) >>> closures2[5](1000) 1005 >>> dis.dis(closures2[5]) 1 0 LOAD_FAST 0 (x) 3 LOAD_DEREF 0 (i) 6 BINARY_ADD 7 RETURN_VALUE >>> closures2[3](1000) 1003 Or same thing without lambda: >>> def mkadd(i): ... def add(x): return x + i ... return add ... >>> closures3 = [mkadd(i) for i in xrange(10)] >>> closures3[5](1000) 1005 >>> closures3[3](1000) 1003 >>> dis.dis(closures3[5]) 2 0 LOAD_FAST 0 (x) 3 LOAD_DEREF 0 (i) 6 BINARY_ADD 7 RETURN_VALUE > >as does Ruby: > >$ ruby -e ' > closures = [] > for i in 0..9 do > closures.push(proc {|x| x + i}) > end > puts closures[5][1000]' >1009 > >but Lisp loses too: > >> (let ((closures (make-array 10))) > (do ((i 0 (+ i 1))) > ((= i 10)) > (setf (svref closures i) #'(lambda (x) (+ x i)))) > (funcall (svref closures 5) 1000)) >1010 > > >Scheme wins: > >> (let ((closures (make-vector 10))) > (do ((i 0 (+ i 1))) > ((= i 10)) > (vector-set! closures i (lambda (x) (+ x i)))) > ((vector-ref closures 5) 1000)) >1005 > >and what is perhaps surprising, Perl wins: > >$ perl -e ' > foreach my $i (0..9) { > push @closures, sub {$_[0] + $i} > } > print $closures[5](1000), "\n"' >1005 > > >If you think it's unlikely that one would want to keep a closure >referring to a loop control variable longer than the loop iteration >which has created it, think about the loop body spawning a thread. > Just do what you need to do. Python usually provides a way ;-) Or do you just want what you want using your idea of the right spelling? ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list