http://qs321.pair.com?node_id=719527


in reply to Re^2: Lexical closures
in thread Lexical closures

The real question is, what do your Scheme and Common Lisp code samples look like?

The Perl behaviour is precisely what I would expect. It generates three closures, each capturing a value of $i. So your first foreach block reduces to:

my @flist = ( sub {0 * $_[0]}, sub {1 * $_[0]}, sub {2 * $_[0]});
It's obvious, then, that 0 2 4 is the correct output of
foreach my $f (@flist) { print $f->(2), "\n"; }

Replies are listed 'Best First'.
Re^4: Lexical closures
by mpeever (Friar) on Oct 25, 2008 at 20:07 UTC

    OK, I took some time to mock out some Scheme: here are both behaviours you've seen:

    (define cclosures (lambda (values) (cond ((null? values) '()) (else (cons (lambda (x) (* (car values) x)) (cclosures (cdr values))))))) (define cclosures2 (let ((val -1)) (lambda (values) (cond ((null? values) '()) (else (begin (set! val (car values)) (cons (lambda (x) (* val x)) (cclosures2 (cdr values))))))))) (define clprint (lambda (closures) (map (lambda (fn) (fn 2)) closures))) > (clprint (cclosures '(0 1 2))) (0 2 4) > (clprint (cclosures2 '(0 1 2))) (4 4 4)

    cclosures uses the equivalent ofdeclaring my $i inside the foreach loop: it defines a new variable called val for every iteration.

    cclosures2 uses the equivalent of declaring my $i outside the foreach loop: val gets reassigned with every iteration.

    Notice the closure closes over the variable, not the value. So when the variable is reassigned, the value inside the closure changes too.

    HTH