I’ve been learning more about the ins and outs of Clojure lately, so I decided to practice a couple of katas. The obvious first one is the Fizz Buzz kata.
Here’s the code of my first take:
(defn fizz? [number] (zero? (rem number 3))) (defn buzz? [number] (zero? (rem number 5))) (defn fizz-buzz? [number] (and (fizz? number) (buzz? number))) (defn fizz-buzz [number] (if (fizz-buzz? number) "fizzbuzz" (if (fizz? number) "fizz" (if (buzz? number) "buzz" number)))) (defn run-fizz-buzz [] (map fizz-buzz (range 1 101)))
For this first attempt, I set out the goal to come up with some very small functions to accomplish the task at hand. This kind of worked out fine except for the fizz-buzz function, which doesn’t feel very idiomatic to me probably caused by the nested if statements.
So for the second attempt, I tried to get rid of these if statements, and this was the result:
(defn fizz? [number] (zero? (rem number 3))) (defn buzz? [number] (zero? (rem number 5))) (defn fizz-buzz? [number] (and (fizz? number) (buzz? number))) (defn fizz-buzz [number] (cond (fizz-buzz? number) "fizzbuzz" (fizz? number) "fizz" (buzz? number) "buzz" :else number)) (defn run-fizz-buzz [] (map fizz-buzz (range 1 101)))
Using the cond macro I was able to remove the nested if statements, and it also slightly reduced the number of parenthesis. So far, so good.
But maybe having so many functions is overkill. So for the next take I wanted to get rid of the fizz?, buzz? and fizz-buzz? functions and move the meat into the fizz-buzz function itself without giving up too much on readability. Here’s the code of my third attempt:
(defn fizz-buzz [number] (let [fizz? (zero? (rem number 3)) buzz? (zero? (rem number 5)) fizz-buzz? (and fizz? buzz?)] (cond fizz-buzz? "fizzbuzz" fizz? "fizz" buzz? "buzz" :else number))) (defn run-fizz-buzz [] (map fizz-buzz (range 1 101)))
Here I used the let special form in order to define the fizz?, buzz? and fizz-buzz? lexical parameter bindings that can then be used inside the expression of the function body. Notice the conciseness of this last attempt compared to the first.
There’s probably someone that could write a single-line function in Clojure that does exactly the same thing, but that’s not the point. Code katas are fun!
Until next time.
I’d have stuck with the second one
I think you’re right that the second one is the most readable. For the last one, I just wanted to find out how a single function would look like, which isn’t too bad either.
Looks good to me Jan. Thanks for sharing. It’s always nice to see someones thought process as they explore a new language.
Glad you like it.