Hmm, upon further investigation I think I would not call this a bug in
Clojure that got fixed, I think I'd call this an unspecified behavior in
Clojure that happened to break your function and now happens to allow it to
work.

Your function depends heavily on Clojure's laziness, and laziness is an
area where Clojure actually does not make a lot of strong guarantees.

Here's an example:

user=> (def r (into [] (range 1000)))
#'user/r
user=> (defn print-and-inc [x] (println x) (inc x))
#'user/print-and-inc
user=> (def s (map print-and-inc r))
#'user/s
user=> (take 1 s)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(1)
user=>

In this example we put a thousand numbers in a vector and call the vector
r, we map print-and-inc over r and then we take one element from the
resulting lazy sequence. You might expect this to mean we print one element
from r, but in fact we print 32. This is because of an optimization detail
in Clojure's map function. It's very easy to extract "chunks" from vectors,
so in Clojure, when we map over a vector, we quickly apply the mapping
function to the first chunk of the vector and return a sequence containing
the result chunk and a promise to map over the rest. In the long run, this
speeds up map quite a bit, but in the short run, it makes map much less
lazy than one might expect.

The upshot is that when a Clojure function promises to consume your list
lazily, you should assume that it will not, say, consume 1000 elements of
your list for no reason, or try to force its way to the end of a lazy
sequence. You should *not* assume you can know exactly when it will force
the next element, as that is essentially considered an implementation
detail.

Returning to your code, you have

(defn primes [] (let [primes' (atom nil)]
                 (reset! primes' (cons 2 (filter #(prime? @primes' %) (drop
3 (range)))))))

When you dereference primes, you're essentially trusting that reset! has
already run and replaced nil with your empty sequence, but in fact you
cannot be certain of that. I can see two ways to ensure your function will
work. One is sort of gratuitous defensive programming -- make your initial
value of primes' something you *wouldn't mind getting*, say

(defn primes [] (let [primes' (atom (drop 2 (range)))]
                 (reset! primes' (cons 2 (filter #(prime? @primes' %) (drop
3 (range)))))))

The other is to wrap your whole expression in lazy-seq -- then reset! will
definitely complete before any of the logic internal to your sequence runs:

(defn primes [] (let [primes' (atom nil)]
                 (lazy-seq (reset! primes' (cons 2 (filter #(prime?
@primes' %) (drop 3 (range))))))))

For anyone wondering, the change was Ghadi's reified range in CLJ-1515
which I seem to recall removed/modified the chunked seq implementation from
range.

On Thu Feb 12 2015 at 12:06:28 PM Jorge Marques Pelizzoni <
jorge.pelizz...@gmail.com> wrote:

> Well, that's a bug then :) And seems to have been fixed. Thanks!
>
> Em quinta-feira, 12 de fevereiro de 2015 17:51:13 UTC-2, Michael Blume
> escreveu:
>
>> Oh, well this is fun -- with bleeding edge clojure I get the right
>> answer, but with 1.6.0 I see the same results you did.
>>
>>
>>  --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to