[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: lexical closure bug?



> (let ((*fun* nil))
>   (do ((a (list 'a 'b 'c 'd 'e) (cdr a)))
>       ((endp a))
>     (push #'(lambda () (format t "~a~%" a)) *fun*))
>   (mapcar #'funcall *fun*))
> 
> I think that this should print out something like:
> 
> (a b c d e)
> (b c d e)
> (c d e)
> (d e)
> (e)
> 
> Instead, it prints:
> nil
> nil
> nil
> nil
> nil
> 
> Am I missing something here?

The result you are seeing is a result of do being implemented by establishing a 
single binding of a and updating it to the next value by side effect on each 
iteration.  So each of your closures is capturing that same single binding, and 
when you invoke the closures the value of the captured binding is nil.  If you 
want distinct bindings for each iteration, you could change your code to 
explicitly establish a new binding within the body of the loop, i.e.

  (let ((*fun* nil))
    (do ((a (list 'a 'b 'c 'd 'e) (cdr a)))
        ((endp a))
      (let ((a a))
        (push #'(lambda () (format t "~a~%" a)) *fun*)))
    (mapcar #'funcall *fun*))

A different implementation of do, which used tail recursion instead of 
tagbody/go and so established a new binding of a for each iteration would have 
produced the result you expected.