4

I'm learning myself some Clojure and I'm using Quil. I would like to know how to translate a for-loop into Clojure:

This is how I would do it in Java or similar languages:

for ( int i = 0; i < numSides; i++ ) {
    float posX = cos( theta * i );
    float posY = sin( theta * i );
    ellipse( posX, posY, polySize, polySize );
}

My Clojure attempt:

  (let [theta (/ PI num-sides)
        angle (range 0 num-sides)
        pos-x (cos (* theta angle))
        pos-y (sin (* theta angle))]
    (dorun (map #(ellipse % % % %) pos-x pos-y poly-size poly-size)))
Dave Liepmann
  • 1,555
  • 1
  • 18
  • 22
Ricardo Sanchez
  • 4,935
  • 11
  • 56
  • 86
  • found similar question here http://stackoverflow.com/questions/9981943/how-to-implement-a-for-loop-in-clojure – Asraful Mar 10 '13 at 09:48

4 Answers4

7

All the ways that you have looked for are basically to work with sequences where as a loop is about executing things for a specific number of times. Clojure provide dotimes to do things for certain number of times:

(dotimes [i 10]
  (println i))

So your code becomes something like:

 (dotimes [i num-sides]
   (let [pos-x (cos (* theta i))
         pos-y (sin (* theta i))]
         (ellipse pos-x pos-y poly-size poly-size)))
Ankur
  • 33,367
  • 2
  • 46
  • 72
4

If you genuinely want an C-style for loop, then my clojure-utils libray has a handy for-loop macro that lets you do stuff like:

(for-loop [i 0 , (< i num-sides) , (inc i)]
  ... do stuff.....)

Normally however, I will find myself using one of the following:

  • (dotimes [i num-sides] ....) - do something a specific number of times
  • (doseq [x some-sequence] ....) - do something for every element in a sequence
  • (for [i (range n)] ...) - constructing a list with n elements
mikera
  • 105,238
  • 25
  • 256
  • 415
  • How about making the macro more C-ish, so that we can do: `(for-loop [ [i 1 j 1] (< i 10) [i (inc i) j (* j i)] ] .....)` – Ankur Mar 10 '13 at 10:40
  • @Ankur interesting idea.... haven't needed that myself but can see the value for some use cases. – mikera Mar 10 '13 at 10:56
2

Perhaps this is somewhat academic, but I like using Clojure's "for comprehensions" for this kind of thing. The code would look like this:

(dorun
  (for [i (range num-sides)
        :let [pos-x (Math/cos (* i theta))
              pos-y (Math/sin (* i theta))]]
    (quil.core/ellipse pos-x pos-y poly-size poly-size)))
mudphone
  • 956
  • 10
  • 9
  • 1
    But `for` is constructing a lazy sequence, unnecessarily, in this case. If you don't need the output sequences, as in this case, you can do the same thing--with the same binding tricks--using `doseq`. Simply replace `for` by `doseq` in the above code. In many situations, the cost of producing the additional sequence is negligible, so that the only advantage of `doseq` is that it communicates to readers that you're not trying to create a sequence. In some situations the cost of creating an unnecessary sequence can make a difference in performance, however. – Mars Aug 23 '14 at 04:37
1

Doseq with range is often appropriate for looping over a specific number of values in order to create side effects. I would implement your loop as follows:

(doseq [i (range 0 num-sides)]
  (ellipse (cos (* theta i)) 
           (sin (* theta i)) 
           poly-size 
           poly-size))
Dave Liepmann
  • 1,555
  • 1
  • 18
  • 22