Erlang FizzBuzz Showdown (Pt 1)

As I've become a little more familiar with Erlang I decided to leave the set text and test myself with a basic (often seen) programming challenge (FizzBuzz) and compare the solution with the languages I'm more familiar with.

FizzBuzz is a pretty simple set of rules (also known as Bizz Buzz) and is used for children's maths, drinking games and as a rather basic test given to programmers during job interviews (although it is so well known that it probably lost its value for this purpose a while back).

The rules (for programmers) are simple:

  • Print a list of numbers 1 - 100
  • If the number is exactly divisible by 3 print "Fizz"
  • If the number is exactly divisible by 5 print "Buzz"
  • If the number is exactly divisible by both 3 and 5 print "FizzBuzz"
  • Otherwise just print the number

Solving the problem breaks down to:

  • Create a range of numbers 1-100
  • Loop through each number and check it against the conditions
  • Print out the result
  • Repeat until 100

So far so simple, it is a pretty straight forward task that can be solved in a broad variety of ways.

Here's how I could achieve this in Python:

for i in range(1,101):
  
  if i % 3 == 0 and i % 5 == 0:
    print 'Fizzbuzz'
        
  elif i % 3 == 0:
    print 'Fizz'
        
  elif i % 5 == 0:
    print 'Buzz'
        
  else:
    print i

And PHP:

foreach (range(1,100) as $i)
{
    if (($i % 5 == 0) && ($i % 3 == 0))
    {
        echo "FizzBuzz\n";
    }
    elseif ($i % 3 == 0)
    {
        echo "Fizz\n";
    }
    elseif ($i % 5 == 0)
    {
        echo "Buzz\n";
    }
    else
    {
        echo "$i\n";
    }
}

Of course there are many variations depending on how short and/or "readable" you'd like it to be.

So, when it came to tackling this problem with Erlang I was a little surprised that I couldn't just launch into it. Approaching this problem functionally is a different kettle of fish. While there are built in functions that can help I chose to ignore them in favour of gaining a little more understanding.

In other languages creating a range of numbers was pretty straight forward and barley registered as a task, in Erlang I needed to think a little harder. There is no for or while loop easily to hand, the solution was a tail-recursive function. It might seem bloated to add this function, but if you compare the same function in Ruby, the Erlang function appears better suited to the task (also using tail recursion in none functional languages causes performance/stack issues so this is more for illustration):

% ERLANG

range(To,To,List) -> List ++ [To];
range(From,To,List) when From  range(From + 1, To, List ++ [From]).
#RUBY

def jRange(from,to,list)
  if from == to
    return list 

Erlang functions can have multiple entry points, so in this case the range function has two entry points:
  • One that accepts two identical values, a list and returns a list with the value added.
  • Another that accepts two different values, a list and adds the first value to the list, then calls the same function (itself) adding one to the first value.

As it matches the incoming conditions there is no need for if or else.

The problem with this loop is that it will go on infinitely if From is greater than To, to cover this we need a guard. This is a simple check that From is less than To:

range(To,To,List) -> [To|List];
range(From,To,List) when From  range(From, To -1, [To|List]).

And now we have an operational "range" function similar to those seen in Python, Ruby and PHP - however, Elang FizzBuzz can use it in various different ways. Another small change was to alter the way the list builds up, using List ++ [From] isn't very efficient and [To|List] does the job more elegantly.

In the next post I'll conclude building a FizzBuzz program (mistakes, solutions and better-practice included), check back tomorrow or subscribe to keep up to date.

Part 2 >>

Meta