Why isn't my code printing like it should?

Tag: clojure , for-loop Author: cestquitoa Date: 2011-08-22

I'm trying to create a for in Clojure.

I'm following the cheats sheet from the Clojure site.

e.g:

(take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))

I'm trying to create my own for which should print "Hello World" 100 times.

(take 100 (for [a (range 100) 
      :while (< a 100)] 
    (println "Hello World")
    )
)

For some reason it's not printing Hello World 100 times. Why not?

There are some good answers already, but I just wanted to point out that "for" in Clojure is not a loop (unlike "for" in Java or C). It is called list comprehension. It's used for constructing lists, not for looping. In this case using dotimes seems to make most sense.

Other Answer1

The most important thing you need to be aware of, is that sequences in Clojure are lazy. That means the items in the sequence are only evaluated when they are needed. This allows you to work with infinite sequences.

Most of the time this is what you want, but it can be confusing when you are not really interested in the values of the sequence items, but in the side-effects of the functions that create the sequence items. In your example, the sequence is made up of 100 return values of the println function, that is 100 times nil - not very interesting. But the println function has the side-effect of printing "Hello World" to stdout.

The problem is, if you never do anything with the items in the sequence, the println functions are never evaluated and the strings are not printed. It kinda works in the REPL, because the P in REPL stands for print - the return value of the expression you typed in is printed. To print the whole sequence, it must be evaluated, so you see a bunch of "Hello World"s, but also a bunch of nils. If you run the code outside of the REPL (without using the returned value), you won't see the Hello Worlds.

If you're interested in the side-effects of your item-generating functions, you can use doall or doseq. doall forces the whole sequence to be evaluated and returns it:

(doall (for [a (range 100)] (println "Hello World")))

doseq doesn't return the sequence (it returns nil) and has a syntax like for:

(doseq [a (range 100)] (println "Hello World"))

Also note that you really only need to supply the desired count (100) once. The range function already produces a sequence with 100 items in it. The :while clause in your code is redundant, as is the take function (taking the first 100 items from a sequence with 100 items doesn't do much).

Hope this helps!

comments:

thank you very much!

Other Answer2

try adding doall in front: The for function creates a lazy sequence, as does take. They may not evaluate until you add a doall.

This little quirk is a common annoyance in Clojure, but makes sense once you get more comfortable with "thinking lazily".

Other Answer3

Actually, it is working for me. The last example does print one hundred "Hello World", but the take gets just one hundred nils that are also printed in the REPL. The first example works as it is:

user=> (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y])) ([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3] [5 0] [5 1] [5 2] [5 3] [5 4] [6 0] [6 1] [6 2] [6 3] [6 4] [6 5] [7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [10 0] [10 1] [10 2] [10 3] [10 4] [10 5] [10 6] [10 7] [10 8] [10 9] [11 0] [11 1] [11 2] [11 3] [11 4] [11 5] [11 6] [11 7] [11 8] [11 9] [11 10] [12 0] [12 1] [12 2] [12 3] [12 4] [12 5] [12 6] [12 7] [12 8] [12 9] [12 10] [12 11] [13 0] [13 1] [13 2] [13 3] [13 4] [13 5] [13 6] [13 7] [13 8] [13 9] [13 10] [13 11] [13 12] [14 0] [14 1] [14 2] [14 3] [14 4] [14 5] [14 6] [14 7] [14 8])

For actually printing, you can try a more easy loop:

(dotimes [i 100] (println "Hello World"))

Finally, if you use for, you don't need the :while, as the range already has 100 elements:

(take 100 (for [a (range 100)] 
               (println "Hello World")))

comments:

exactly, the first example works and print it... but this example is from clojure site... I need create my own for wich must print 100 times Hello World... but It is just not working for me =/
What about the dotimes I added?
actually I must use For ... it must present this command to some folks... your dotimes works perfectly, but I need a code using for to print Hello World :X
thank you very much for helping me
Well, using for then, the only way is just how you were doing it. It actually prints one hundred "Hello World" messages. It just also returns the 100 collected nil values of the println.