/img/clojure-banner.png

Diamonds, Printing, and Run!

Solving the diamond kata led to some new discoveries

Written by: Alex Root-Roatch | Saturday, June 15, 2024

The Diamond Kata

The diamond kata is a fun coding challenge that involves creating a function that creates a diamond with letters up to the given letter. For example:

(print-diamond "D")

    A
   B B
  C   C
 D     D
  C   C
   B B
    A

There are two main parts to figure out: calculating the amount of leading spaces for each line, and figuring out the amount of spaces between each character to achieve the desired width.

The first part is relatively easy: the amount of leading spaces to put the "A" in place is equal to the number of unique letters in the diamond, so that's four for the above example. The amount decreases by one per line until we get to the middle of the diamond.

The second part is a little trickier: the number of spaces between each letter is 1 for the B's, 3 for the C's, and 5 for the D's. For more letters, we would continue up the sequence of odd numbers. To do this programmatically, we can consider each line as an index, with the A's being line 0, the B's being line 1, and so on. This approach works well when using a vector to store all the letters of the alphabet, where index 0 is A. Then, take that number, subtract one, and add it to the original number. So for the C's being line 2, 2 + (2-1) = 3. For the D's, 3 + (3-1) = 5.

For actually printing the diamond, I started off wanting to use println for every line of the diamond. That might be okay for a small diamond, but if were to enter in "Z" as our argument, we would invoke println 51 times! With some quick experimenting in the REPL, though, I found out that println parses new line characters \n as line breaks instead of simply printing the character. For example:

(println " A\nB B\n A")
 A
B B
 A 

That's much friendlier than invoking println for every line of the diamond.

Leveraging Side Effects with Run!

While I was still thinking about using println for every line, I had tried using map to iterate through a vector of strings, each string being a line of the diamond, and print it to the console. This did indeed still print every line to the console, but it made my tests fail because map returns the value of running its callback function on each element, and println doesn't have a return value. As a result, a vector of four strings returned [nil nil nil nil].

This made me wonder if there was a version of map or reduce that didn't return anything. In JavaScript, there's map and forEach. map does the same thing as map in Clojure, but forEach has no return value and is good when all you're doing on each iteration is a side effect rather than an operation on the value itself.

After posing this question to my mentor, he pointed out the run! function. Notice the exclamation? In Clojure, that is how we denote that a function has side effects. run! essentially runs reduce on the given collection purely for the sake of side effects, and changing my map call to run! fixed my failing tests!

However, this is not an approach I would recommend for this kata for the reasons stated in the above section.

Explore more articles

Browse All Posts