Clojure: Living Without the For Loop (3)

In this part of our series about transforming imperative Processing code into functional Clojure code we are deconstructing a ‘real’ loop for the first time. The code to be discussed is taken from Matt Pearson’s book ‘Generative Art‘, and we are using Quil for accessing the power of Processing in Clojure. Our focus is less on understanding the math behind the images drawn but on the different approach when it comes to functional and data-driven programming.

Last time the Processing code used the implicit loop hidden behind Processing’s draw method. We solved this with a loop/recur construct and obtained the same result. This time we are turning the screw a bit more with a while loop.

This is what we want:

2015-05-24_00-54-49

Well, that’s at least a bit more interesting than this lonely circle in the last part. Drawing concentric circles can be done with this Processing code:

The draw() method paints a circle, followed by further circles within that outer one. Then the canvas is cleared and the whole procedure repeats until the diameter has reached 400. This is not an overly elegant solution, and an improved version will follow immediately, but we are not talking about efficiency at this time. Let us focus on the draw() method once more, especially its inner while loop. Here additional circles are drawn with decreasing diameters starting at size diam.

This is my solution in Clojure:

We already have seen most of the initialization work in defsketch and setup; the bindings for the symbols cent-x and cent-y have been moved to draw, because we need them there.

Most of draw’s part is built like we did last time: we are repeatedly drawing a circle until it reaches a diameter of 400 pixels. This is done in the outer loop that is repeatedly targeted by recur, binding diam to a value increased by 10. The when condition breaks as soon as diam is reaching a value of 400. The inner loop first binds a symbol tempdiam to the recent value of diam, checks for tempdiam’s size and possibly draws a circle. Then we are entering the inner loop: this one also expects a parameter tempdiam, starting with the value of diam. It is repeatedly evaluated with a decreased (by 10) tempdiam while tempdiam is greater than 10.

But drawing concentric cirlces can be done a lot easier. Have a look at this code:

In our first example we were drawing a circle, then its inner circles, then repeating this until the diameter reaches 400 pixels. In this second improved version we are just drawing circles by increasing the diameter by 10. This omits the permanent cleaning and redrawing of the image at each step. Here is the appropriate Clojure code:

This code is much simpler and looks a lot like the code we discussed last time. The only thing missing is the erasing of the background in draw. This way each new circle is simply drawn above all others, resulting in the same figure. When you replace the (no-fill) with (fill 255 25) in the last line of setup, then you are getting this result:

2015-05-24_10-38-40

About Manfred Berndtgen

Manfred Berndtgen, maintainer of this site, is a part-time researcher with enough spare time for doing useless things and sharing them with the rest of the world. His main photographic subjects are made of plants or stones, and since he's learning Haskell everything seems functional to him.