Confused about closures and scoping rules

Jakub Hegenbart kyosuke at kimagure.cz
Thu Nov 8 02:02:51 EST 2007


On Wed, 07 Nov 2007 01:37:00 +0100, Chris Mellon <arkanes at gmail.com> wrote:

> Are there languages where closures *don't* behave like this? A closure
> that used a copy of the state rather than the actual state itself
> doesn't seem as useful. For references sake, JavaScript (the only
> language that a) has closures and b) I have a handy way to test with)
> does the same thing.

The results in an equivalent code might depend on the semantics of the
looping construct used. For example, take Scheme (I'm using Gauche Scheme):

(define (outer-1 nmax)
   (let ((aa '()))
	(dotimes (n nmax)
	  (push! aa (lambda (y) (list "y:" y "n:" n))))
	aa))

(define (outer-2 nmax)
   (let ((aa '())
		(n 0))
	(until (= n nmax)
	  (push! aa (lambda (y) (list "y:" y "n:" n)))
	  (set! n (+ n 1)))
	aa))

(print (map (lambda (f) (f 1)) (outer-1 5)))
(print (map (lambda (f) (f 1)) (outer-2 5)))

$ gosh closures.scm
((y: 1 n: 4) (y: 1 n: 3) (y: 1 n: 2) (y: 1 n: 1) (y: 1 n: 0))
((y: 1 n: 5) (y: 1 n: 5) (y: 1 n: 5) (y: 1 n: 5) (y: 1 n: 5))

In outer-1, the (dotimes ...) form expands into (do ...). R5RS defines
that a (do ...) loop is expected to _rebound_ all of its state variables
(here it is only n) in each iteration step. This means that each closure
created captures a different binding. Whereas in outer-2, I am updating
the binding destructively, so the value changes in the environment of
all the closures that have been already stored. Python seems to do the
latter. (I am not a pythonist right now, but I am learning... :))

Regards,

Jakub



More information about the Python-list mailing list