Hi Evan,
Thanks for the reply.
I tried putting a print and it works as expected.
(let [a (atom 0)
i (take-while (fn[x] (swap! a inc)
(< x 100)) [1 2 3 4 5])]
(println i)
[@a i]) ;; <== [5 (1 2 3 4 5)]
But, I still cant come up with a theory of what exactly is happening.
My understanding of laziness is not deep enough, but I had ruled it out
initially for 2 reasons
1) I assumed that printing out [i @a] instead of [@a i] should realize
*'i'*first and @a should be correctly displayed as 5. This does not happen, it
simply prints [(1 2 3 4 5) 0] if the order is reversed.
2) If I put a breakpoint in the predicate for take-while, it gets hit ( I
was expecting it to not get hit if it was lazy)
3) This is the strangest observation of all: In the debugger I can see that
*'a' *is getting incremented, its changing when the breakpoint is hit! but
the baffling thing is, when the result is printed out, I still get 0 as the
value for a.
Now if a print is added, I am seeing 5 correctly printed out, but I am not
satisfied with any explanation I can make up.
Isn't (print i) the same as [i @a] ? since i is realized first, shouldn't
@a be correctly printed?
Why is the breakpoint showing me that a is changing ? What is totally
strange is that '0' gets printed for @a in the end in spite of the change
that I saw while debugging. I find this baffling as I was expecting the
clojure runtime to have 'forgotten' about the earlier value since it is a
single variable 'bound' to a single value (a --> 0) if a number gets 'put'
as its value, as then it would become (a --> 5) how did it go 'back' to
becoming 0 again after I saw its value changing in the debugger ?
Here is the code for this behavior ( with emacs / lein / swank and a
swank,core/break breakpoint)
(let [a (atom 0)
i (take-while (fn[x] (swap! a inc) (swank.core/break) ;; <== this
shows values like : a = #<Atom@4ee2af00: 1>, a = #<Atom@4ee2af00: 2>, a =
#<Atom@4ee2af00: 3> etc
(< x 100)) [1 2 3 4 5])]
[i @a]) ;; <== But, this prints out [(1 2 3 4 5) 0]
I am reasonably sure there is no persistent data structure involved as it
is an atom. By that reasoning, there should be no memory of '0'. Is there
something else I am missing ? Is this normal lazy behavior ?
Thanks
Vinay
On Tuesday, 31 July 2012 08:54:02 UTC+5:30, Evan Mezeske wrote:
>
> The problem is that take-while is lazy, so it does not actually perform
> the "taking" operation until the lazy-seq it returns is realized, e.g. by
> being printed. So when your code binds the (take-while ...) expression to
> "i", the anonymous function you provided is not yet being invoked, and thus
> the atom's value is not being incremented.
>
> Since your code dereferences the "a" atom before it forces evaluation of
> the "i" lazy-seq, it gets the value 0. The "a" atom's value will only be 5
> after "i" has been fully realized, which happens later.
>
> So, for example, if you changed your code to this:
>
> (let [a (atom 0)
> i (take-while (fn[x] (swap! a inc) (< x 100)) [1 2 3 4 5])]
> (println i)
> (println @a))
>
> You will see the result you expect, because println forces "i" to be fully
> realized, and thus "a" will be changed as a side-effect.
>
> In general, performing side-effecty operations inside lazy code is not
> usually advisable, because due to the nature of laziness, the results will
> not be what you'd expect if you were coming from a, say,
> imperative-language background.
>
> Perhaps someone else can provide a link to some good reading material for
> learning about laziness?
>
>>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en