is this a portable CL? (rebind)



Hello, All!

suppose i want to collect a list of closures i want to evaluate later:

(loop for obj in objects
collect (lambda () (process obj)))

however, this won't work correctly -- all closures will refer to one
variable OBJ in LOOP code, so with typical LOOP implementation they will all
have last OBJ value.

[3]> (loop for fun in
(loop for obj in '(1 2 3 4 5)
collect (lambda () obj))
collect (funcall fun))

(5 5 5 5 5)

to avoid this behaviour, i rebind variable with LET:

(loop for obj in objects
collect (let ((obj obj))
collect (lambda () (process obj))))

this really helps:

CL-USER> (loop for fun in
(loop for obj in '(1 2 3 4 5)
collect (let ((obj obj)) (lambda () obj)))
collect (funcall fun))
(1 2 3 4 5)

however, i'm not sure that this fix works according to Common Lisp standard.
i think it is, as LET creates new variable binding (i could call it other
name), and each closure points to it's own binding.

however at least in one implemenation (ABCL) in compiled mode it doesn't
work:

CL-USER> (funcall (compile nil (lambda () (loop for fun in
(loop for o in '(1 2 3 4 5)
collect (let ((o2 o)) (lambda () o2)))
collect (funcall fun)))))

(5 5 5 5 5)

while all other implementations i've tested (CLISP, SBCL, ACL, Lispworks)
produce expected output
(1 2 3 4 5), at least with default compiler settings.

ABCL implementation maintainer (Peter Graves) suggests to use backquote to
form a list instead of closure, which i find a bit ugly. he says it's a
question if compiler has to propagate constants.
while i believe my version should be correct according to the semantics
about how bindings and closures work.

i appreciate if somebody can clarify this, pointing to paragraphs of
standard specifying which behaviour is correct.

With best regards, Alex Mizrahi.


.