Lisp-likeness

Marcin 'Qrczak' Kowalczyk qrczak at knm.org.pl
Wed Mar 16 00:36:40 CET 2005


tar at sevak.isi.edu (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

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.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak at knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/



More information about the Python-list mailing list