From: Johan Ur Riise on 22 Apr 2010 21:42 Another reason to hate loop: (defun closures-from-loop (list) (loop for el in list collect (lambda () (format t "~s~%" el)))) (loop for lambda in (closures-from-loop (list 1 2 3 'a 'b 'c)) do (funcall lambda)) prints, since heavy setq-ing is going on behind the scene curtain: C C C C C C NIL (defun closures-from-mapcar (list) (mapcar (lambda (el) (lambda () (format t "~s~%" el))) list)) (mapcar #'funcall (closures-from-mapcar (list 1 2 3 'a 'b 'c))) prints: 1 2 3 A B C (NIL NIL NIL NIL NIL NIL) Of course, when you find the bug you can also say: (defun closures-from-loop (list) (let (result) (loop for el in list do (let ((el el)) (push (lambda () (format t "~s~%" el)) result))) (reverse result)))
From: Alberto Riva on 22 Apr 2010 22:17 Johan Ur Riise wrote: > Another reason to hate loop: > > (defun closures-from-loop (list) > (loop for el in list collect (lambda () (format t "~s~%" el)))) > > (loop for lambda in (closures-from-loop (list 1 2 3 'a 'b 'c)) > do (funcall lambda)) > > prints, since heavy setq-ing is going on behind the scene curtain: > > C > C > C > C > C > C I don't see why you were expecting anything different. There's a single 'el' variable, and all closures are capturing it. Try doing this: (let ((a 1)) (list (lambda () (print a)) (incf a) (lambda () (print a)))) and then funcall the first and third elements of the resulting list: it will print 2 in both cases. It doesn't have to do with LOOP. > (defun closures-from-mapcar (list) > (mapcar (lambda (el) (lambda () (format t "~s~%" el))) list)) > > (mapcar #'funcall (closures-from-mapcar (list 1 2 3 'a 'b 'c))) In this case, the "(lambda (el) ..." makes it clear that you're introducing a new local variable every time. > prints: > > 1 > 2 > 3 > A > B > C > (NIL NIL NIL NIL NIL NIL) > > > Of course, when you find the bug Where did you see a bug? > you can also say: > > (defun closures-from-loop (list) > (let (result) > (loop for el in list do > (let ((el el)) > (push (lambda () (format t "~s~%" el)) result))) > (reverse result))) Which is exactly what your MAPCAR example does: create a new local variable every time. You could have obtained the same result much more simply this way: (defun closures-from-loop (list) (loop for el in list collect (let ((el2 el)) (lambda () (print el2))))) Alberto
From: Johan Ur Riise on 22 Apr 2010 22:27 Alberto Riva <ariva(a)nospam.ufl.edu> writes: > Johan Ur Riise wrote: >> Another reason to hate loop: >> >> (defun closures-from-loop (list) >> (loop for el in list collect (lambda () (format t "~s~%" el)))) >> >> (loop for lambda in (closures-from-loop (list 1 2 3 'a 'b 'c)) >> do (funcall lambda)) >> >> prints, since heavy setq-ing is going on behind the scene curtain: >> >> C >> C >> C >> C >> C >> C > > I don't see why you were expecting anything different. There's a > single 'el' variable, and all closures are capturing it. I didn't notice that fact, that's why I didn't expect it >Try doing > this: > > (let ((a 1)) > (list (lambda () (print a)) > (incf a) > (lambda () (print a)))) > > and then funcall the first and third elements of the resulting list: > it will print 2 in both cases. It doesn't have to do with LOOP. > >> (defun closures-from-mapcar (list) >> (mapcar (lambda (el) (lambda () (format t "~s~%" el))) list)) >> >> (mapcar #'funcall (closures-from-mapcar (list 1 2 3 'a 'b 'c))) > > In this case, the "(lambda (el) ..." makes it clear that you're > introducing a new local variable every time. > >> prints: >> >> 1 >> 2 >> 3 >> A >> B >> C >> (NIL NIL NIL NIL NIL NIL) >> >> >> Of course, when you find the bug > > Where did you see a bug? > >> you can also say: >> >> (defun closures-from-loop (list) >> (let (result) >> (loop for el in list do (let ((el el)) (push >> (lambda () (format t "~s~%" el)) result))) >> (reverse result))) > > Which is exactly what your MAPCAR example does: create a new local > variable every time. You could have obtained the same result much more > simply this way: > > (defun closures-from-loop (list) > (loop > for el in list > collect (let ((el2 el)) (lambda () (print el2))))) Better than the result/let/push/reverse solution, thanks, but also collect (let ((el el)) (lambda () (print el))) is nice
From: Barry Margolin on 22 Apr 2010 23:23 In article <874oj30wrj.fsf(a)morr.riise-data.net>, Johan Ur Riise <johan(a)riise-data.no> wrote: > Another reason to hate loop: > > (defun closures-from-loop (list) > (loop for el in list collect (lambda () (format t "~s~%" el)))) > > (loop for lambda in (closures-from-loop (list 1 2 3 'a 'b 'c)) > do (funcall lambda)) > > prints, since heavy setq-ing is going on behind the scene curtain: > > C > C > C > C > C > C > NIL DO, DOLIST, and DOTIMES behave the same way. Why single out LOOP? -- Barry Margolin, barmar(a)alum.mit.edu Arlington, MA *** PLEASE post questions in newsgroups, not directly to me *** *** PLEASE don't copy me on replies, I'll read them in the group ***
From: Tamas K Papp on 23 Apr 2010 03:02
On Fri, 23 Apr 2010 03:42:56 +0200, Johan Ur Riise wrote: > Another reason to hate loop: > > (defun closures-from-loop (list) > (loop for el in list collect (lambda () (format t "~s~%" el)))) > > (loop for lambda in (closures-from-loop (list 1 2 3 'a 'b 'c)) > do (funcall lambda)) > > prints, since heavy setq-ing is going on behind the scene curtain: > > C > C > C > C > C > C > NIL > > > > (defun closures-from-mapcar (list) > (mapcar (lambda (el) (lambda () (format t "~s~%" el))) list)) > > (mapcar #'funcall (closures-from-mapcar (list 1 2 3 'a 'b 'c))) > > prints: > > 1 > 2 > 3 > A > B > C > (NIL NIL NIL NIL NIL NIL) > > > Of course, when you find the bug you can also say: > > (defun closures-from-loop (list) > (let (result) > (loop for el in list do > (let ((el el)) > (push (lambda () (format t "~s~%" el)) result))) > (reverse result))) There is no bug, just a misunderstanding on your part. Unlike Scheme, CL iteration constructs are not required to have a different variable for each iteration of the loop body. There have been many discussions on this topic, see eg http://coding.derkeiler.com/Archive/Lisp/comp.lang.lisp/2008-10/msg01003.html Just use (defun closures-from-loop (list) (loop for el in list collect (let ((el el)) (lambda () (format t "~s~%" el))))) Tamas PS.: If a widely used construct in a language that was standardized 10+ years ago fails to conform to my expectations, I would read the manual really carefully before calling it a bug. |