Sunday, June 29, 2014

Exercism: "Nucleotide count in Clojure"

This is my solution to the Nucleotide count problem in Clojure:

(ns dna)
(def nucleotides #{\A, \T, \C, \G, \U})
(defn nucleotide-counts [strand]
(let
[count
(fn [counted-nucleotides nucleotide]
(assoc
counted-nucleotides
nucleotide
(+ (get counted-nucleotides nucleotide) 1)))]
(reduce count {\A 0, \T 0, \C 0, \G 0} strand)))
(defn count [nucleotide strand]
(if (contains? nucleotides nucleotide)
(get (nucleotide-counts strand) nucleotide 0)
(throw (Exception. "invalid nucleotide"))))

The code is very similar to the one for the Word count exercise. The main difference is that here I used a set to validate that the given nucleotide is valid.

I eliminated the duplication between the set and the map contents in this second version:

(ns dna)
(def dna-nucleotides #{\A, \T, \C, \G})
(def nucleotides (conj dna-nucleotides \U))
(defn nucleotide-counts [strand]
(let
[counted-nucleotides
(zipmap dna-nucleotides (repeat (count dna-nucleotides) 0))
count
(fn [counted-nucleotides nucleotide]
(assoc
counted-nucleotides
nucleotide
(+ (get counted-nucleotides nucleotide) 1)))]
(reduce count counted-nucleotides strand)))
(defn count [nucleotide strand]
(if (contains? nucleotides nucleotide)
(get (nucleotide-counts strand) nucleotide 0)
(throw (Exception. "invalid nucleotide"))))

where I defined a set containing only DNA nucleotides, dna-nucleotides, that I used to define the nucletides set using conj. This dna-nucleotides set served to generate the counted-nucleotides map using the zipmap function.

Trying to avoid duplication I discovered several new things about Clojure.

You can nitpick my solution here or see all the exercises I've done so far in this repository.

--------------------------------

Update:

After learning some new stuff, I've been able to simplify the code a bit more:

(ns dna)
(def ^:private dna-nucleotides #{\A, \T, \C, \G})
(def ^:private nucleotides (conj dna-nucleotides \U))
(defn nucleotide-counts [strand]
(merge {\A 0, \T 0, \C 0, \G 0} (frequencies strand)))
(defn count [nucleotide strand]
(if (contains? nucleotides nucleotide)
(get (nucleotide-counts strand) nucleotide 0)
(throw (Exception. "invalid nucleotide"))))

It turned out that the frequencies function already did the counting out of the box, I jut needed to merge it with the result for an empty strand to make frequencies output conform with what the tests were expecting.

I also made the dna-nucleotides and nucleotides sets private.

You can nitpick this new version here.

Saturday, June 28, 2014

Exercism: "Beer song in Clojure"

This is my solution to the Beer song problem in Clojure:

I wrote a first version using just regular functions:

(ns beer
(:require [clojure.string :as str]))
(defn no-more-bottles? [num-of-bottles]
(= num-of-bottles 0))
(defn one-bottle? [num-of-bottles]
(= num-of-bottles 1))
(defn bottles [num-of-bottles]
(cond
(no-more-bottles? num-of-bottles) "no more bottles"
(one-bottle? num-of-bottles) (str num-of-bottles " bottle")
:else (str num-of-bottles " bottles")))
(defn bottles-of-beer [num-of-bottles]
(str (bottles num-of-bottles) " of beer"))
(defn bottles-on-the-wall [num-of-bottles]
(str (bottles-of-beer num-of-bottles) " on the wall"))
(defn phrase1 [num-of-bottles]
(str (str/capitalize (bottles-on-the-wall num-of-bottles))
", "
(bottles-of-beer num-of-bottles)
".\n"))
(defn take-down [num-of-bottles]
(str
"Take "
(if (one-bottle? num-of-bottles) "it" "one")
" down and pass it around, "))
(defn action [num-of-bottles]
(if (no-more-bottles? num-of-bottles)
"Go to the store and buy some more, "
(take-down num-of-bottles)))
(defn remaining-bottles [num-of-bottles]
(if (no-more-bottles? num-of-bottles)
99
(- num-of-bottles 1)))
(defn phrase2 [num-of-bottles]
(str (action num-of-bottles)
(bottles-on-the-wall
(remaining-bottles num-of-bottles))
".\n"))
(defn verse [num-of-bottles]
(str (phrase1 num-of-bottles)
(phrase2 num-of-bottles)))
(defn closed-descending-range [from to]
(reverse (range to (inc from))))
(defn sing
([from]
(sing from 0))
([from to]
(str/join
"\n"
(map verse (closed-descending-range from to)))))
view raw beer1.clj hosted with ❤ by GitHub

and a second one using multimethods:

(ns beer
(:require [clojure.string :as str]))
(def on-the-wall " on the wall")
(def of-beer " of beer")
(defn sth-of-beer [text]
(str text of-beer))
(defn sth-on-the-wall [text]
(str (sth-of-beer text) on-the-wall))
(defn take-down [which]
(str "Take " which " down and pass it around"))
(defn beer-phrase
([f text]
(beer-phrase f text ""))
([f text plural]
(f (str text " bottle" plural))))
(defn paragraph [phrase1 phrase2]
(str phrase1 ", " phrase2 ".\n"))
(defn first-paragraph
([text]
(first-paragraph text ""))
([text plural]
(paragraph
(str/capitalize (beer-phrase sth-on-the-wall text plural))
(beer-phrase sth-of-beer text plural))))
(defn second-paragraph
([action text]
(second-paragraph action text ""))
([action text plural]
(paragraph
action
(beer-phrase sth-on-the-wall text plural))))
(defmulti verse identity)
(defmethod verse 0 [_]
(str
(first-paragraph "no more" "s")
(second-paragraph
"Go to the store and buy some more" 99 "s")))
(defmethod verse 1 [num-of-bottles]
(str
(first-paragraph num-of-bottles)
(second-paragraph
(take-down "it") "no more" "s")))
(defmethod verse 2 [num-of-bottles]
(str
(first-paragraph num-of-bottles "s")
(second-paragraph
(take-down "one") (- num-of-bottles 1))))
(defmethod verse :default [num-of-bottles]
(str
(first-paragraph num-of-bottles "s")
(second-paragraph
(take-down "one") (- num-of-bottles 1) "s")))
(defn closed-descending-range [from to]
(reverse (range to (inc from))))
(defn sing
([from]
(sing from 0))
([from to]
(str/join
"\n"
(map verse (closed-descending-range from to)))))
view raw beer2.clj hosted with ❤ by GitHub

I enjoyed refactoring the code once all tests were passing.
I also practised how to use multimethods and how to pass parameters with default values.

You can nitpick my solution here or see all the exercises I've done so far in this repository.

Friday, June 27, 2014

Exercism: "Anagram in Clojure"

This is my solution to the Anagram problem in Clojure:

(ns anagram
[:require [clojure.string :as str]])
(defn anagram? [word possible-anagram]
(and
(not= word possible-anagram)
(= (sort possible-anagram)
(sort word))))
(defn case-insensitive-anagram? [word possible-anagram]
(anagram?
(str/lower-case word)
(str/lower-case possible-anagram)))
(defn anagrams-for [word word-list]
(vec
(filter
#(case-insensitive-anagram? word %)
word-list)))
view raw anagram.clj hosted with ❤ by GitHub

This time I decided not to make the helpers local because they might be useful by themselves.
I also decided to separate in different functions the case-sensitive and case-insensitive versions of the anagram detection function.

You can nitpick my solution here or see all the exercises I've done so far in this repository.

Exercism: "Rna Transcription in Clojure"

This is my solution to the Rna Transcription problem in Clojure:

(ns dna)
(defn to-rna [nucleotides]
(let
[transcribe
(fn [nucleotide]
(let [transcriptions {\C \G
\G \C
\A \U
\T \A}
transcribed (get transcriptions
nucleotide)]
(if (nil? transcribed)
(throw (AssertionError.))
transcribed)))]
(apply str (map transcribe nucleotides))))
view raw dna.clj hosted with ❤ by GitHub

I used a map to look-up the transcription of each nucleotide.

The AssertionError exception was necessary to pass the provided tests. I would have rather used a different exception.

You can nitpick my solution here or see all the exercises I've done so far in this repository.

--------------------------------

Update:

After learning some new stuff, I've been able to simplify the code a bit more:

(ns dna)
(def ^:private transcriptions
{\C \G
\G \C
\A \U
\T \A})
(defn- transcribe [nucleotide]
(if-let
[transcribed (get transcriptions nucleotide)]
transcribed
(throw (AssertionError.))))
(defn to-rna [nucleotides]
(apply str (map transcribe nucleotides)))
view raw dna2.clj hosted with ❤ by GitHub

I used the if-let form, def ^:private and the defn- macro in order to improve readability

You can nitpick this new version here.

Thursday, June 26, 2014

Exercism: "Word count in Clojure"

This is my solution to the Word count problem in Clojure:

(ns word-count
(:require [clojure.string :as str]))
(defn word-count [sentence]
(let
[count-word-occurrences
(fn [counted-words word]
(let
[add-new-word
(fn [] (assoc counted-words word 1))
add-occurrence-to-word
(fn [] (assoc counted-words word
(+ (get counted-words word) 1)))]
(if (contains? counted-words word)
(add-occurrence-to-word)
(add-new-word))))
extract-words-from
(fn [sentence]
(let
[remove-punctuation (comp (partial apply str)
(partial filter
#(or (Character/isLetter %)
(Character/isSpace %)
(Character/isDigit %))))]
(str/split
(remove-punctuation
(str/lower-case sentence)) #"\s+")))]
(reduce
count-word-occurrences
{}
(extract-words-from sentence))))
view raw word-count.clj hosted with ❤ by GitHub

I created some local helpers and played with partial and comp to make the code more readable.
I also reduced the number of parameters of some local helpers by using some free variables.

I really liked how the reduce function can be applied to a map data-structure in Clojure.

You can nitpick my code here.

--------------------------------

Update:

After learning some new stuff, I've been able to simplify the code a bit more:

(ns word-count
(:require [clojure.string :as str]))
(defn- extract-words-from [sentence]
(let
[remove-punctuation
(comp (partial apply str)
(partial filter
#(or (Character/isLetter %)
(Character/isSpace %)
(Character/isDigit %))))]
(str/split (remove-punctuation (str/lower-case sentence)) #"\s+")))
(defn word-count [sentence]
(frequencies (extract-words-from sentence)))
view raw word-count1.clj hosted with ❤ by GitHub

I used the frequencies function to count each word frequency and the defn- special macro to make extract-words-from function private.

You can nitpick this new version here.

Wednesday, June 25, 2014

Exercism: "Hamming distance in Ruby"

This is my solution to the Hamming problem in Ruby:

class Hamming
def self.compute(strand1, strand2)
def self.base_distance(base1, base2)
def self.both_exists?(base1, base2)
not [base1, base2].any? {|base| base.nil?}
end
(both_exists?(base1, base2) and base1 != base2) ? 1 : 0
end
strand1.chars.zip(strand2.chars).map do |base1, base2|
base_distance(base1, base2)
end.reduce(:+)
end
end
view raw hamming.rb hosted with ❤ by GitHub
I tried to improve readability by creating the helper class methods base_distance and both_exists?. I also wanted to play a bit with map and reduce.

You can see two other versions here. I used zip in all of them.

This exercise served me to practice a bit with some Ruby collection functions.

Exercism: "Bob in Clojure"

This is my solution to the Bob problem in Clojure:

(ns bob
(:require [clojure.string :as str]))
(defn response-for [sentence]
(let
[shouting?
(fn []
(let
[letters (filter #(Character/isLetter %) sentence)]
(and (not (empty? letters))
(every? #(Character/isUpperCase %) letters))))
asking?
(fn []
(= (last sentence) \?))
saying-nothing? #(str/blank? sentence)]
(cond
(shouting?) "Woah, chill out!"
(asking?) "Sure."
(saying-nothing?) "Fine. Be that way!"
:else "Whatever.")))
view raw bob.clj hosted with ❤ by GitHub

I just used cons and created some local helpers to make the code more readable.

You can see two other versions here.

This exercise served me to practice a bit with regular expressions and to discover some new useful Clojure functions.

Sunday, June 22, 2014

Interesting Talk: "467 tests, 0 failures, 0 confidence"

I've just watched this wonderful talk by Katrina Owen: She talks about a practical application of Sandi Metz's "magic" testing tricks and what those heuristics can tell you about your design.

Exercism.io

This weekend I've started working through the Exercism exercises.

First of all, I'd like to thank Katrina Owen for starting this wonderful project.

Exercism is a great open source project that she started in order to "provide a space to think deeply about simple, expressive, and readable code, and experiment and discuss what good looks like".

There are exercises in many languages but I'm only working on the Clojure and Ruby ones.

Even though the exercises have been very simple so far, they've helped me to practise and learn more about Clojure's and Ruby's powerful collection and string functions.

I've also learned some tricks and functions I didn't know by looking at the solutions to the same exercises posted by other people. As soon as I gain enough confidence in Clojure and Ruby I will start giving them feedback.

I hope to start receiving some feedback about my solutions in order to improve them.

Here you can find the few exercises I've done so far.

Interesting Talk: "Steve Freeman On TDD: How Do We Know When We’re Done?"

I've just watched this great talk by Steve Freeman:

Sunday, June 15, 2014

Saturday, June 14, 2014

Interesting Talk: "Testable Javascript"

I've just watched this great talk by Mark Ethan Trostler in which he describes some great principles, techniques and patterns to make your JavaScript code more testable:
He is also the author of the Testable Javascript book.

------------------------

PS: This other version of the talk is also great.

Kata: Berlin Clock in Clojure with Midje

I did the Berlin Clock kata in Clojure using Midje.

These are the tests:

(ns berlin_clock.t-core
(:use midje.sweet)
(:use [berlin_clock.core]))
(use '[clojure.string :only (join)])
(facts "about Berlin Clock"
(facts "seconds lamp"
(fact "It turns on for one second (Y)"
(show "00:00:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"]))
(fact "It turns off for the next second (O)"
(show "00:00:01") => (join "\n"
["O"
"OOOO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])))
(facts "hours lamps first row"
(fact "it contains 4 lamps that represent 5 hours each when red (R)"
(show "05:00:00") => (join "\n"
["Y"
"ROOO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])
(show "10:00:00") => (join "\n"
["Y"
"RROO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])
(show "15:00:00") => (join "\n"
["Y"
"RRRO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])))
(facts "hours lamps second row"
(fact "it contains 4 lamps that represent 1 hour each when red (R)"
(show "06:00:00") => (join "\n"
["Y"
"ROOO"
"ROOO"
"OOOOOOOOOOO"
"OOOO"])
(show "22:00:00") => (join "\n"
["Y"
"RRRR"
"RROO"
"OOOOOOOOOOO"
"OOOO"])
(show "14:00:00") => (join "\n"
["Y"
"RROO"
"RRRR"
"OOOOOOOOOOO"
"OOOO"])))
(facts "minutes lamps first row"
(fact "it contains 11 lamps that repesents 5 minute each,
every 3rd lamp is red but the rest are yellow"
(show "00:15:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"OOOO"])
(show "00:50:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYRYYRYYRYO"
"OOOO"])))
(facts "minutes lamps second row"
(fact "it contains 4 yellow lamps that represents 1 minute each"
(show "00:16:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"YOOO"])
(show "00:18:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"YYYO"])
(show "00:19:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"YYYY"]))))

And this is the final version of the code:

(ns berlin_clock.core)
(use '[clojure.string :only (join split)])
(defn show [time]
(let
[[h m s] (map #(Integer. %) (split time #":"))
turn-on-red (fn [num-lamps] (repeat num-lamps "R"))
turn-on-yellow (fn [num-lamps] (repeat num-lamps "Y"))
turn-off (fn [num-lamps] (repeat num-lamps "O"))
turn-on-YYR (fn [num-lamps-on]
(take num-lamps-on (cycle ["Y" "Y" "R"])))
show (comp (partial apply str) concat)
show-lamps (fn [num-lamps-on num-lamps turn-on]
(let [num-lamps-off (- num-lamps
num-lamps-on)]
(show (turn-on num-lamps-on)
(turn-off num-lamps-off))))
seconds (if (zero? (rem s 2)) "Y" "O")
hours-first-row (show-lamps (quot h 5) 4 turn-on-red)
hours-second-row (show-lamps (rem h 5) 4 turn-on-red)
minutes-first-row (show-lamps (quot m 5) 11 turn-on-YYR)
minutes-second-row (show-lamps (rem m 5) 4 turn-on-yellow)]
(join "\n"
[seconds
hours-first-row
hours-second-row
minutes-first-row
minutes-second-row])))

I used a mix of TDD and REPL-driven development.

To document the process I commited the code after every passing test and every refactor.
I also commited the .lein-repl-history file so that you can see all the micro-tests I did on the REPL to create some of the features and learn about Clojure including many beginner mistakes :)

You can find the resulting code in this GitHub repository.

Wednesday, June 11, 2014

Protractor: How to click a select option that has a given value

Today I needed to click on a select option that had a specific value using protractor.
After Googling for a while, I did it using the element selection by xpath.
This is the helper function I created:

var TestTools = {
// some other helpers
// ...
clickDropdownOptionWithGivenValue: function (
selectId, optionValue) {
element(by.css('#' + selectId)).click();
return element(
by.xpath(
'//select[@id="' + selectId +
'"]/option[text()="' + optionValue + '"]')
).click();
}
};
// some other exports
// ...
module.exports.clickDropdownOptionWithGivenValue = TestTools.clickDropdownOptionWithGivenValue;


And this is how it's used from the test:

describe("In the project details page", function () {
var TestTools = require('./TestTools'),
Navigation = require('./Navigation'),
ptor;
beforeEach(function () {
TestTools.resetTestData();
ptor = protractor.getInstance();
ptor.get('/ebo/#/projects/excecutive-education');
Navigation.logIn(ptor);
TestTools.waitForElementByCssToBePresent(
'.project-item__title', ptor);
});
// some other tests
// ...
it("A landing gets duplicated", function () {
expect(
element.all(
by.repeater('landing in project.landings')).count()
).toBe(6);
element.all(by.css('.duplicate')).first().click();
element(by.css('#input_duplicate_new_name')).sendKeys("new_name");
TestTools.clickDropdownOptionWithGivenValue(
'project-name-select', 'Excecutive Education'
).then(function () {
element(by.css('.button_big')).click();
expect(
element.all(
by.repeater('landing in project.landings')
).count()
).toBe(7);
}
);
});
});


----------------

PS: Check also my previous posts about Protractor:

Monday, June 9, 2014

Protractor: How to select a dropdown option to avoid ElementNotVisibleError

Another problem we found last week using protractor was when we tried to click on a dropdown option.

This was the problematic code:

describe("A project landings list page", function () {
var TestTools = require('./TestTools'),
Navigation = require('./Navigation'),
ptor;
beforeEach(function () {
TestTools.resetTestData();
ptor = protractor.getInstance();
ptor.get('/ebo/#/projects/excecutive-education');
Navigation.logIn(ptor);
TestTools.waitForElementByCssToBePresent('.project-item__title', ptor);
});
// some tests ...
it("shows a new 'autoresponder' mailing", function () {
element(by.css('#new_ma')).click(); // <- produces an error
expect(ptor.getCurrentUrl())
.toMatch('/projects/excecutive-education/new-mailing/ma');
});
});

which caused the following error:
ElementNotVisibleError: element not visible

This happened because the element we were trying to click on was hidden.

Googling a bit again, we found (here) that to avoid the error we had to click on the dropdown before clicking on the option to open it up, so that it wa visible to the user:

it("shows a new 'autoresponder' mailing", function () {
element(by.css('.dropdown .new_mailings')).click(); // <- this fixes it
element(by.css('#new_ma'))
.click().then(function () {
expect(ptor.getCurrentUrl())
.toMatch(
'/projects/excecutive-education/new-mailing/ma'
);
}
);
});

Again we extracted this bit of code into a helper method in out TestTools module:

it("shows a new 'autoresponder' mailing", function () {
TestTools.clickDropdownOption( // <- helper
'.dropdown .new_mailings', '#new_ma'
).then(function () {
expect(ptor.getCurrentUrl())
.toMatch(
'/projects/excecutive-education/new-mailing/ma'
);
}
);
});

----------------

PS: Check also my previous post about Protractor:

Protractor: How to avoid UnexpectedAlertOpenError

At work, we've recently started to use protractor to write end-to-end tests for a legacy AngularJs code base.

Last week we found a problem while trying to test that an element from a list was deleted:

describe("A project landings list page", function () {
var TestTools = require('./TestTools'),
Navigation = require('./Navigation'),
ptor;
beforeEach(function () {
TestTools.resetTestData();
ptor = protractor.getInstance();
ptor.get('/ebo/#/projects/excecutive-education');
Navigation.logIn(ptor);
TestTools.waitForElementByCssToBePresent('.project-item__title', ptor);
});
it("lists all landings and mailings", function () {
var landingsAndMailings = element.all(
by.repeater('landing in project.landings')),
mailings = element.all(
by.repeater('mailing in project.landings | filter:{mailing:true}'));
landingsAndMailings.count().then(function (landingsAndMailingsNumber) {
mailings.count().then(function (mailingsNumber) {
var landingsNumbers = landingsAndMailingsNumber - mailingsNumber;
expect(mailingsNumber).toBe(4);
expect(landingsNumbers).toBe(2);
});
});
});
it("removes a landing", function () {
element.all(by.css('.delete')).first().click(); // <- the problem happens here
expect(
element.all(
by.repeater('landing in project.landings')).count()
).toBe(5);
});
// some other tests
});

The problem was that clicking on the delete icon was displaying an alert box, prompting the user to confirm whether they actually wanted to delete the element or not, that protractor didn't expect and was causing the following error:
UnexpectedAlertOpenError: unexpected alert open

After searching in Google for a while, we found a solution:

it("removes a landing", function () {
element.all(by.css('.delete')).first().click();
ptor.driver.switchTo().alert().then( // <- this fixes the problem
function (alert) {
alert.accept();
},
function (error) {
}
);
expect(
element.all(
by.repeater('landing in project.landings')).count()
).toBe(5);
});

that fixed the problem by switching to the alert box and confirming that we wanted to delete the element.

Since it was a bit verbose and we'd probably have to use it again in some other tests, we extracted it to a helper function in our TestTools module:

it("removes a landing", function () {
element.all(by.css('.delete')).first().click();
TestTools.switchToAlertAndAccept(ptor); // <- the fix is now in a helper function
expect(
element.all(
by.repeater('landing in project.landings')).count()
).toBe(5);
});

I hope you might find this useful if you're using protractor.

Sunday, June 8, 2014

Practising Clojure sequences using FizzBuzz and REPL Driven Development

I recently blogged about my version of the FizzBuzz kata in Clojure using Midje comparing it with a version I did some time ago in Racket's Advanced Student Language.

Even though both solutions were very similar, doing the kata this time in Clojure was useful to practise with Midje.

To try to get to a different solution for the kata and use the Clojure sequence library, I set myself a constraint:
Instead of mapping just a function on the sequence of numbers, I had to find several transformations that could be mapped one after another on sequences to get the same result.

Since I had to do a lot of trial and error, I prefered to use REPL Driven Development this time.

This was the REPL session to get to the first alternative version (eliminating a lot of errors..):

user=> (range 1 16)
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
user=> (defn is-multiple-of? [num n]
#_=> (= 0 (rem n num)))
#'user/is-multiple-of?
user=> (def is-multiple-of-3?
#_=> (partial is-multiple-of? 3))
#'user/is-multiple-of-3?
user=> (is-multiple-of-3? 3)
true
user=> (is-multiple-of-3? 5)
false
user=> (def is-multiple-of-5?
#_=> (partial is-multiple-of? 5))
#'user/is-multiple-of-5?
user=> (is-multiple-of-5? 3)
false
user=> (is-multiple-of-5? 5)
true
user=> (defn fizz [n s]
#_=> (if (is-multiple-of-3? n)
#_=> (str s "Fizz")
#_=> s))
#'user/fizz
user=> (fizz 3 "")
"Fizz"
user=> (fizz 4 "")
""
user=> (defn buzz [n s]
#_=> (if (is-multiple-of-5? n)
#_=> (str s "Buzz")
#_=> s))
#'user/buzz
user=> (buzz 3 "")
""
user=> (buzz 5 "")
"Buzz"
user=> (map fizz (range 1 16) (repeat 16 ""))
("" "" "Fizz" "" "" "Fizz" "" "" "Fizz" "" "" "Fizz" "" "" "Fizz")
user=> (map buzz (range 1 16) (repeat 16 ""))
("" "" "" "" "Buzz" "" "" "" "" "Buzz" "" "" "" "" "Buzz")
user=> (map (fn [n s] (if (= s "") (str n) s))
#_=> (range 1 16)
#_=> (map buzz (range 1 16) (map fizz (range 1 16) (repeat 16 ""))))
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")
user=> (defn empty-str-to-number [n s]
#_=> (if (= s "") (str n) s))
#'user/empty-str-to-number
user=> (map empty-str-to-number ; <- recursive application of map
#_=> (range 1 16)
#_=> (map buzz
#_=> (range 1 16)
#_=> (map fizz
#_=> (range 1 16)
#_=> (repeat 16 ""))))
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")
user=> (def transformations (list fizz buzz empty-str-to-number))
#'user/transformations
user=> (defn transform [functions numbers strings]
#_=> (if (empty? functions)
#_=> strings
#_=> (recur (rest functions) numbers (map (first functions) numbers strings))))
#'user/transform
user=> (transform transformations (range 1 16) (repeat 16 ""))
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")
user=> (def a-vec [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15])
#'user/a-vec
user=> (transform transformations a-vec (repeat (count a-vec) ""))
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")
user=> (defn fiz-buzz-numbers [coll transformations]
#_=> (let [transform (fn [functions numbers result]
#_=> (if (empty? functions)
#_=> result
#_=> (recur (rest functions)
#_=> numbers
#_=> (map (first functions) numbers result))))]
#_=> (transform transformations coll (repeat (count coll) ""))))
#'user/fiz-buzz-numbers
user=> (fiz-buzz-numbers a-vec transformations)
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")

From this REPL session I got this alternative version for fizz-buzz:

(defn fizz-buzz [coll]
(let [is-multiple-of? (fn [num n]
(= 0 (rem n num)))
is-multiple-of-3? (partial is-multiple-of? 3)
is-multiple-of-5? (partial is-multiple-of? 5)
fizz (fn [n s]
(if (is-multiple-of-3? n)
(str s "Fizz")
s))
buzz (fn [n s]
(if (is-multiple-of-5? n)
(str s "Buzz")
s))
empty-str-to-number (fn [n s]
(if (= s "")
(str n)
s))
transformations (list fizz buzz empty-str-to-number)
transform (fn [functions numbers result]
(if (empty? functions)
result
(recur (rest functions)
numbers
(map (first functions) numbers result))))]
(clojure.string/join
\space
(transform transformations coll (repeat (count coll) "")))))

It's more complicated that the original version but it served me to practise some interesting Clojure features: recur, partial, map and let.

Then I tried a different approach:
Reducing the sequence of transformation functions so that I can map the resulting transformation function on the sequence of numbers.

Again I worked in the REPL first:

user=> (defn is-multiple-of? [num n]
#_=> (= 0 (rem n num)))
#'user/is-multiple-of?
user=> (def is-multiple-of-3?
#_=> (partial is-multiple-of? 3))
#'user/is-multiple-of-3?
user=> (def is-multiple-of-5?
#_=> (partial is-multiple-of? 5))
#'user/is-multiple-of-5?
user=> (def a-vec [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15])
#'user/a-vec
user=> (defn fizz [n s]
#_=> [n (if (is-multiple-of-3? n)
#_=> (str s "Fizz")
#_=> s)])
#'user/fizz
user=> (fizz 3 "")
[3 "Fizz"]
user=> (defn buzz [[n s]]
#_=> [n (if (is-multiple-of-5? n)
#_=> (str s "Buzz")
#_=> s)])
#'user/buzz
user=> (buzz [5 ""])
[5 "Buzz"]
user=> (defn empty-str-to-number [[n s]]
#_=> (if (= s "") (str n) s))
#'user/empty-str-to-number
user=> (def t (reduce comp (reverse [fizz buzz empty-str-to-number])))
#'user/t
user=> (t 1 "")
"1"
user=> (t 3 "")
"Fizz"
user=> (t 5 "")
"Buzz"
user=> (t 15 "")
"FizzBuzz"
user=> (map t a-vec (repeat (count a-vec) ""))
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")
user=> (defn fizz2 [[n s]]
#_=> [n (if (is-multiple-of-3? n)
#_=> (str s "Fizz")
#_=> s)])
#'user/fizz2
user=> (fizz2 [3 ""])
[3 "Fizz"]
user=> (def t2 (reduce comp (reverse [fizz2 buzz empty-str-to-number])))
#'user/t2
user=> (for [n a-vec s [""]] [n s])
([1 ""] [2 ""] [3 ""] [4 ""] [5 ""] [6 ""] [7 ""] [8 ""] [9 ""] [10 ""] [11 ""] [12 ""] [13 ""] [14 ""] [15 ""])
user=> (map t2 (for [n a-vec s [""]] [n s]))
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz")

From this second REPL session I got this other alternative version for fizz-buzz:

(defn fizz-buzz [coll]
(let [is-multiple-of? (fn [num n]
(= 0 (rem n num)))
is-multiple-of-3? (partial is-multiple-of? 3)
is-multiple-of-5? (partial is-multiple-of? 5)
fizz (fn [[n s]]
[n (if (is-multiple-of-3? n)
(str s "Fizz")
s)])
buzz (fn [[n s]]
[n (if (is-multiple-of-5? n)
(str s "Buzz")
s)])
empty-str-to-number (fn [[n s]]
(if (= s "") (str n) s))
transformations (list fizz buzz empty-str-to-number)]
(clojure.string/join
\space
(map
(reduce comp (reverse transformations))
(for [n coll s [""]] [n s])))))

which is again more complicated than the original version but served me to work with other intersting Clojure's features: reduce, comp and reverse.

After these two versions of FizzBuzz I did a web search to find nicer ways to use the Clojure's sequence library to implement FizzBuzz and I found these two in Rosseta Code that I specially like (I modified them a bit so they return the same that the precious versions):

(defn fizz-buzz [coll]
(clojure.string/join
\space
(map (fn [n]
(if-let [fb (seq (concat (when (zero? (mod n 3)) "Fizz")
(when (zero? (mod n 5)) "Buzz")))]
(apply str fb)
(str n)))
coll)))

(defn fizz-buzz [coll]
(clojure.string/join
\space
(map #(let [s (str %2 %3) ]
(if (seq s)
s
(str %)))
coll
(cycle [ "" "" "Fizz" ])
(cycle [ "" "" "" "" "Buzz" ]))))

These two last versions will serve me to learn about if-let and cycle.

Ok, that was all I got today.

Just to sum up, I think there is a lot you can get from even a simple kata like FizzBuzz if you set yourself some constraints and try different variations.

--------------------------------------------------

PS: You'll find other variations of FizzBuzz kata in these previous posts: this one and this other one.

Kata: FizzBuzz in Clojure with Midje

I did the FizzBuzz kata in Clojure using Midje.
You can find the resulting code in GitHub.

I love Midje's readability. Look at the tests:

(ns fizz_buzz.t-core
(:use midje.sweet)
(:use [fizz_buzz.core]))
(facts "About fizz-buzz-number"
(fact "A number that is not a multiple of
neither 3 nor 5
is turned into a string"
(fizz-buzz-number 1) => "1"
(fizz-buzz-number 2) => "2")
(fact "A number that is a multiple of 3
is turned into 'Fizz'"
(fizz-buzz-number 3) => "Fizz"
(fizz-buzz-number 9) => "Fizz")
(fact "A number that is a multiple of 5
is turned into 'Buzz'"
(fizz-buzz-number 5) => "Buzz"
(fizz-buzz-number 25) => "Buzz")
(fact "A number that is a multiple of
3 and 5 is turned into 'FizzBuzz'"
(fizz-buzz-number 15) => "FizzBuzz"))
(facts "About fizz-buzz"
(fact "An empty collection of numbers is
turned into an empty string"
(fizz-buzz []) => "")
(fact "A collection of numbers is turned into
a string of words separated by spaces
where each word resulted from applying
fizz-buzz-number"
(fizz-buzz (range 1 16)) =>
"1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz"))

This is the FizzBuzz code in Clojure:

(ns fizz_buzz.core)
(defn fizz-buzz-number [num]
(let [is-multiple-of? (fn [n] (= 0 (rem num n)))
a-multiple-of-3 (is-multiple-of? 3)
a-multiple-of-5 (is-multiple-of? 5)
a-multiple-of-both (and a-multiple-of-3
a-multiple-of-5)]
(cond
a-multiple-of-both "FizzBuzz"
a-multiple-of-3 "Fizz"
a-multiple-of-5 "Buzz"
:else (str num))))
(defn fizz-buzz [coll]
(clojure.string/join
\space
(map fizz-buzz-number coll)))
view raw fizzbuzz.clj hosted with ❤ by GitHub

Compare it to this version I did in Racket's Advanced Student Language some time ago:

#reader(lib "htdp-advanced-reader.ss" "lang")((modname fizzbuzz) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #t #t none #f ())))
(check-expect (fizz-buzz empty) empty)
(check-expect (fizz-buzz (list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))
(list "1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz" "16"))
(define (fizz-buzz loi)
(if (empty? loi) loi
(cons (translate (first loi))
(fizz-buzz (rest loi)))))
(check-expect (translate 1) "1")
(check-expect (translate 3) "Fizz")
(check-expect (translate 6) "Fizz")
(check-expect (translate 5) "Buzz")
(check-expect (translate 10) "Buzz")
(check-expect (translate 15) "FizzBuzz")
(define (translate num)
(local [(define (multiple-of-3? num)
(zero? (remainder num 3)))
(define (multiple-of-5? num)
(zero? (remainder num 5)))
(define (multiple-of-3-and-5? num)
(and (multiple-of-3? num)
(multiple-of-5? num)))]
(cond [(multiple-of-3-and-5? num) "FizzBuzz"]
[(multiple-of-3? num) "Fizz"]
[(multiple-of-5? num) "Buzz"]
[else (number->string num)])))
view raw fizzbuzz.rkt hosted with ❤ by GitHub

They are more or less the same (except that Clojure's version returns a string whereas Racket's one returns a list of strings).

On one hand, I prefer Clojure's cond which is more readable because it's more lenient with the parentheses.

On the other hand, I really like how Racket's local allows to define local functions inside another function in the same way they are defined in a module.
In Clojure I also defined a local function is-multiple-of? using let but the result is less readable than using Racket's local.

Update: I keep on working on this kata on the next post, Practising Clojure sequences using FizzBuzz and REPL Driven Development.