(let ((list '((a . 2) (b . 3) (c . 4))))
(loop for (name . value) in list
collect
(lambda ()
value)))
then do:
(loop for f in * do
(format t "~s~%" (funcall f)))
and you will get:
4
4
4
However, I hoped to get
2
3
4
I wrote it with mapcar
(mapcar #'(lambda (x) (lambda () (cdr x))) '((a . 2) (b . 3) (c . 4)))
but would like to know if one could write this with loop (l find loop
in general rather intuitiv) ?
> this is counter-intuitiv
>
> (let ((list '((a . 2) (b . 3) (c . 4))))
> (loop for (name . value) in list
> collect
> (lambda ()
> value)))
> then do:
> (loop for f in * do
> (format t "~s~%" (funcall f)))
> and you will get:
> 4
> 4
> 4
> However, I hoped to get
> 2
> 3
> 4
This is because there's just one VALUE variable, which gets reassigned
each time through the loop. It's not a new binding each time.
The same thing happens with DO and its variants.
>
> I wrote it with mapcar
> (mapcar #'(lambda (x) (lambda () (cdr x))) '((a . 2) (b . 3) (c . 4)))
> but would like to know if one could write this with loop (l find loop
> in general rather intuitiv) ?
(loop for (name . value) in list
collect
(let ((value value))
(lambda () value)))
--
Barry Margolin, bar...@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 ***
> this is counter-intuitiv
>
> (let ((list '((a . 2) (b . 3) (c . 4))))
> (loop for (name . value) in list
> collect
> (lambda ()
> value)))
This is not counter-intuitive, this is implementation dependant.
To get implementation independant behavior, you should rebind the loop
variables:
(let ((list '((a . 2) (b . 3) (c . 4))))
(loop
:for (name . value) :in list
:collect (let ((value value))
(lambda () value))))
--
__Pascal Bourguignon__
collect (constantly value)))
Pascal
--
ELS'09: http://www.european-lisp-symposium.org/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Then why does this work?:
(let ((list '((a . 2) (b . 3) (c . 4))))
(loop for (name . value) in list
collect
value))
And doesn't lambda generate implicit a let-environment? Then why does
you example work and not my original, naiv first code?
Man, I never stop learning?!?
And if that didn't make sense, read:
http://www.flownet.com/ron/specials.pdf
rg
this just collects values.
ob> And doesn't lambda generate implicit a let-environment?
there is no "implicit a let-environment".
lambda creates a closure. closure is essentially a pair -- a reference
to the code and a list of references to a bindings, that is, places where
variables are stored. when loop starts, it established such bindings
for variables, but only once -- rather than creating a new binding on
each iteration, it just assigns value to existing bindings, as it is
typically
more efficient. thus, all closures you generate are exactly same -- they all
reference same code and same list of bindings, and so they all return
same value.
if you do a (let ((value value)) a new binding is created for each
iteration,
so closure reference different bindings, and it works correctly.
returning to your question, lambda CANNOT establish new bindings
for variables it references because that will violate semantics -- for some
uses it is critical for closures to see same variables, it won't be possible
if it will make its own bindings.
however, LOOP could create new bindings for each iteration, but usually
it does not.
CL-USER 1 > (let ((list '((a . 2) (b . 3) (c . 4))))
(loop for (name . value) in list
collect
(funcall (lambda (value)
(lambda () value))
value)))
(#<anonymous interpreted function 22180F2A> #<anonymous interpreted
function 22299E12> #<anonymous interpreted function 22180F5A>)
CL-USER 2 > (loop for f in * do
(format t "~s~%" (funcall f)))
2
3
4
NIL
--------------
John Thingstad
Clojure:
user=> (map second '((a 2) (b 3) (c 4)))
(2 3 4)
OCaml:
# List.map snd [("a",2);("b",3);("c",4)];;
- : int list = [2; 3; 4]
> Clojure:
>
> user=> (map second '((a 2) (b 3) (c 4)))
> (2 3 4)
This is the right solution, but just for fun:
if you were following the idiomatic way and used vectors
instead of lists then:
user> (map #(% 1) '[[a 10] [b 2] [c 8] [d 39] [e -6]])
(10 2 8 39 -6)
user> (map #(% 2) '[[a true 2] [b false 3] [c true 4]])
(2 3 4)
André
--
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org/
> And doesn't lambda generate implicit a let-environment?
Of course not. Consider:
(defvar *getter*)
(defvar *setter*)
(multiple-value-setq (*getter* *setter*)
(let ((a 1))
(values (lambda () a)
(lambda (new-val) (setq a new-val)))))
The two lambdas have to share the same environment for this to be useful.
Your LOOP is similar, except that the two lambdas are from successive
iterations. But they're still closed over the same environment, because
there's no new binding of the free variable they reference.
> Clojure:
> user=> (map second '((a 2) (b 3) (c 4)))
> (2 3 4)
The specification was to return a list of closures, you peasant
drunkard.
Cheers,
Pillsy
> The specification was to return a list of closures, you peasant
> drunkard.
exactly. here is is in clojure so we don't have to see yet another (re)
turn of the screw(ball):
user=> (def fn-list (let [l '[[a 2] [b 3] [c 4]]] (for [[name value]
l] (fn [] value))))
#'user/fn-list
user=> (doseq [item (map #(%) fn-list)] (println item))
2
3
4
nil
user=>
>Clojure:
>
>user=> (map second '((a 2) (b 3) (c 4)))
>(2 3 4)
>
>OCaml:
>
># List.map snd [("a",2);("b",3);("c",4)];;
>- : int list = [2; 3; 4]
What about MatzLisp? You don't like it anymore?
--
|Don't believe this - you're not worthless ,gr---------.ru
|It's us against millions and we can't take them all... | ue il |
|But we can take them on! | @ma |
| (A Wilhelm Scream - The Rip) |______________|
That reeks to high heaven. Why does c.l.l. have the worst code
in the universe? Is it because CommuneLisp sucks or because
CommuneLispers suck? Probably both.
That reeks to high heaven. Why does c.l.l. have the worst code
You are not solving the same problem.
What you wrote would be
(mapcar #'second '((a 2)(b 3)(c 4)))
or
(loop for (name . value) in list collect value)
Which is more readable.
His code returns a function that when called will return that value.
--------------
John Thingstad
> > That reeks to high heaven.
> You are not solving the same problem.
> What you wrote would be
... etc etc
He's right, everyone's wrong; he can't can't see what's in front of
his nose; everything stinks: the obvious diagnosis is that his head
has got jammed somewhere.
Nothing we can do to help.
Tom SW
You are not returning a list of closures. An equivalent solution with
mapcar would be what someone else posted already:
(mapcar (lambda (cell)
(lambda () (cdr cell)))
'((a . 2) (b . 3) (c . 4)))
I don't see how that `reeks to high heaven', but it does what the OP
wanted to do, either with cons cells:
[5]> (defparameter *foo*
(mapcar (lambda (cell) (lambda () (cdr cell)))
'((a . 2) (b . 3) (c . 4))))
*FOO*
[6]> (mapcar #'funcall *foo*)
(2 3 4)
or with lists:
[7]> (defparameter *foo*
(mapcar (lambda (cell) (lambda () (second cell)))
'((a 2) (b 3) (c 4)))))
*FOO*
[8]> (mapcar #'funcall *foo*)
(2 3 4)
`Commune Lisp' seems to work fine, so nice troll but no cookie...
WJ> That reeks to high heaven. Why does c.l.l. have the worst code
WJ> in the universe? Is it because CommuneLisp sucks or because
WJ> CommuneLispers suck? Probably both.
WJ> Clojure:
WJ> user=> (map second '((a 2)(b 3)(c 4)))
WJ> (2 3 4)
don't you think that the point of that code was not to
return a list of numbers, but to show how to create
closures in a loop? because, you know, if we'd really
be interested in generating list of three numbers, we'd
just write '(2 3 4).
please stop posting these small code snippets without
understanding even a bit what is all this about. this
is really annoying.
What about
(let ((list '((a . 2) (b . 3) (c . 4))))
(loop for x in list collect (constantly (cdr x))))
When I (mapcar #'funcall over-the-result) I get ==> (2 3 4).
Is that also implementation dependant?
It's not implementation dependant, it's the same as collecting values
As someone mentioned, the closures returned all close over the same
variable, because the loop just establishes a single binding updating
its value on each iteration.
Sometimes that is just what we want; sometimes it is not.
The quickest way to "repair" the above unwanted behavior is another
nested 'let' as follows:
(let ((list '((a . 2) (b . 3) (c . 4))))
(loop for (name . value) in list
collect
(let ((temp value))
(lambda () temp))))
> Pascal J. Bourguignon schrieb:
>> olivier...@gmail.com writes:
>>
>>> this is counter-intuitiv
>>>
>>> (let ((list '((a . 2) (b . 3) (c . 4))))
>>> (loop for (name . value) in list
>>> collect
>>> (lambda ()
>>> value)))
>> This is not counter-intuitive, this is implementation dependant.
>> To get implementation independant behavior, you should rebind the
>> loop
>> variables:
>> (let ((list '((a . 2) (b . 3) (c . 4))))
>> (loop
>> :for (name . value) :in list
>> :collect (let ((value value))
>> (lambda () value))))
>>
>
> What about
> (let ((list '((a . 2) (b . 3) (c . 4))))
> (loop for x in list collect (constantly (cdr x))))
It's a perfectly good solution, in this simple case.
CONSTANTLY is a function, and (cdr x) will be bound automatically to
the parameter of CONSTANTLY.
If you want to avoid introducing explicit bindings, you can go further:
(import 'com.informatimago.common-lisp.utility:compose)
(mapcar (compose constantly cdr) '((a . 2) (b . 3) (c . 4)))
(mapcar (function funcall) *)
Then it's only a matter of defining more higher level functions so you
can implement any algorithm without citing any variable or parameter.
http://www.thocp.net/biographies/papers/backus_turingaward_lecture.pdf
> When I (mapcar #'funcall over-the-result) I get ==> (2 3 4).
> Is that also implementation dependant?
Not at all, it's perfectly conformant code.
--
__Pascal Bourguignon__
Arc:
arc> (map cdr '((a . 2)(b . 3)(c . 4)))
(2 3 4)
I don't think so. You need to get a list of closures, not a list of numbers.