views:

236

answers:

2

When length is 4 following loop executes 5 times. Reading 5 characters from the stream.


(loop [i (.read stream)  result ""  counter length]
    (let [c (char i)]
      (println "=>" c)
      (if (zero? counter)
        result
        (recur (.read stream) (str result c) (dec counter)))))
A: 

I don't know clojure, but it looks to me like you're reading the stream again in "result" form, is this like final in CL ?

simon
+3  A: 

You should test for zero? before you do the read. Note that your version will call read once even if length == 0 to begin with.

(loop [result "" counter length]
  (if (zero? counter)
    result
    (let [c (char (.read stream))]
      (println "=>" c )
      (recur (str result c) (dec counter)))))

Another way which avoids an explicit loop:

(apply str 
       (take length 
             (repeatedly #(let [c (char (.read stream))]
                            (println "=>" c) c)))))
Brian Carper
So i should add another test before the loop for zero but i still don't get why it is running 5 times? is this the clojure behavior or am i missing something?
Hamza Yerlikaya
Your version does the read when counter = 4, 3, 2, 1, 0. That's five iterations. The first read is done inside the loop bindings vector to set up `i` initially, and the next four reads are done via `recur`. By the time you test `counter` for `zero?` you've already done one read too many. The version I posted moves the read inside the if-statement, which avoids this problem. You don't need another test before the loop.
Brian Carper
Step through your loop in your head, you will see where the 5th character comes from. Basically, repeating the same thing (.read stream) at two places in the loop is a code smell.
Svante