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))) 
1

4 Answers 4

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))) 
Sign up to request clarification or add additional context in comments.

Comments

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

2 Comments

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 interesting idea.... haven't needed that myself but can see the value for some use cases.
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))) 

1 Comment

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.
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)) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.