3 ms·
(def fizzbuzz-nums (range 1 101)) (defn fizz? [n] (zero? (% n))) (defn buzz? [n] (zero? (% n 5))) (defn fizzbuzz? [n] (and (fizz? n) (buzz? n)))
by Slackwise 8y ago
(def fizzbuzz-nums (range 1 101))
(defn fizz? [n] (zero? (% n)))
(defn buzz? [n] (zero? (% n 5)))
(defn fizzbuzz? [n] (and (fizz? n) (buzz? n)))
(defn fizzbuzz [n]
(cond (fizzbuzz? n) "FizzBuzz"
(fizz? n) "Fizz"
(buzz? n) "Buzz"
:else n)))
(def fizzbuzz-list (map fizzbuzz fizzbuzz-nums))
(apply println fizzbuzz-list)
- christophilus 8y agoSimple. But this brings up a debate I've been having with some folks. I have the memory of a gnat, so I can't keep a lot of context in my head. I prefer the previous two examples to this one, simply because with this one, I have to remember a lot more contextual vocabulary. It's a pet-peeve of mine to pull up a source file, and then have to ping-pong around between 50 different function calls, when the entire thing could have been written linearly in fewer than 50 lines of code. On the other hand, small functions like yours are easier to verify at a glance and move on. I haven't figured out what the right trade-off is. Anyone else want to weigh in on this conundrum?
- evdubs 8y agoWell, I would say that the primary refactoring done in Slackwise's example is just to assign names to the different conditions and the list produced by range. I think it makes most sense to break these things out and assign them to names when they both become a common idiom in your code (it is used in multiple places) and the logic spans a few lines or has sufficient complexity. I, too, would rather look at one piece of code than have to find out what each function is attempting to do if the name is perhaps ambiguous. For Slackwise's example, I would say that that is too much abstraction because you've basically created as many pieces of abstraction (the conditionals and list) as there were lines of code without them. Maybe the decision for when to abstract can boil down to: * Is a common idiom in the code base / same logic used in multiple places * Has "sufficient" complexity * Can be replaced with a good name that is generally clear with what it will achieve For Slackwise's example, I think that the names used in the abstractions are exactly what I would use, but I also think that they're not really descriptive enough. If I wasn't the original author and thought I should refactor the names, I would probably try to choose divisible-by-3?, divisible-by-5?, and divisible-by-15? because what the hell is a fizz or a buzz anyway? Maybe you had already thought about all of this and wanted a deeper response; sorry to disappoint.