A bonus Erlang Thursday for everyone today.
This past weekend I came across the post Bro, Do You Even FizzBuzz?!? about solving FizzBuzz in Clojure without using the modulus operator.
After translating it to Ruby as a point for a co-worker and publishing that translation, I thought I would translate it to Erlang as well to see the difference.
-module(fizzbuzz). -export([fizzbuzz/1]). fizzbuzz(N) -> Results = do_fizzbuzz(N), lists:foreach(fun(X) -> io:format("~p~n", [X]) end, Results). do_fizzbuzz(N) -> Fizzes = cycle(["", "", "fizz"], N), Buzzes = cycle(["", "", "", "", "buzz"], N), FizzBuzzes = lists:zipwith(fun lists:append/2, Fizzes, Buzzes), Numbers = lists:seq(1, N), lists:zipwith(fun translate/2, Numbers, FizzBuzzes). cycle(List, N) -> lists:sublist(lists:append(lists:duplicate(N, List)), N). translate(Number, "") -> integer_to_list(Number); translate(_, Translation) -> Translation.
A couple of points to note in the Erlang solution.
First, Erlang doesn’t have any direct concept of lazy lists/sequences, and there is no
cycle function, so I had to improvise by calling
lists:sublist a list that cycles over the source list to create a list that has
N elements. While this is not exactly the most efficient way to do this, it shows that it can be done.
Second, the ability of using
lists:zipwith helps with some of the ideas of pipelining, as we can process the items as they are zipped together, instead of having to process them as a different step.
Third, instead of using a case statement, we can use a function with a guard clause to determine if a translation exists or not, and use the translation if so, and the number if not.
I hope this gives you some food for thought, and would love to hear your feedback on how this could be improved even more, or other ways that FizzBuzz can be done besides the usual pattern matching with the guard clauses checking the remainders.