Actually, the control flow only requires you to know that you've done SOMETHING out of the ordinary, but not WHAT you've done. A C example that is easily extensible:<p><pre><code> void fizzBuzz(void)
{
bool alternateUsed = false;
for(int i = 1; i <= 100; i++)
{
if(i % 3 == 0)
{
printf("Fizz");
alternateUsed = true;
}
if(i % 5 == 0)
{
printf("Buzz");
alternateUsed = true;
}
if(!alternateUsed)
{
printf("%d", i);
}
printf("\n");
alternateUsed = false;
}
}
</code></pre>
All you need to know for the decision to print the bare number is whether an alternate (Fizz or Buzz) was used in this iteration. Furthermore, FizzBuzz is described such that you stack alternates (FizzBuzz for values that are multiples of 3 and 5). In this example, they stack automatically, with the order of "if" statements determining the priority. Want to change it to print "BuzzBazzFizz" for multiples of 5, 4, and 3? No problem!<p><pre><code> if(i % 5 == 0)
{
printf("Buzz");
alternateUsed = true;
}
if(i % 4 == 0)
{
printf("Bazz");
alternateUsed = true;
}
if(i % 3 == 0)
{
printf("Fizz");
alternateUsed = true;
}
</code></pre>
Yes, imperative languages can be a bit cumbersome at times, but elegant solutions are still possible.
I don't entirely like his generalized fizz buzz (with the printers and such), because it doesn't capture the way I read the requirements well.<p>The requirements to me read as: I have pairs of number-sets and strings, and whenever a number is divisible by all numbers in the set, the application is supposed to output the associated string. If multiple sets of numbers fulfill this property, the string associated with the largest set is used. If no group matches, output the number. Note that this specification contains a loophole: What if one set is [1, 2] and the other set is [2, 4] and the number is 4? This is undefined.<p>From such a data structure, deriving the generalized program is rather simple and straightforward and from there, I don't entirely see the reason to go nuts with functional programming and category theory and whatsoever, because the generalized solution is a rather simple folding operation and the biggest complications come from the hole in the spec.
This seems a far more obvious way to code the extensible case:<p><pre><code> def fizzbuzz(max)
(1..max).each do |n|
labels = []
labels << "fizz" if n % 3 == 0
labels << "buzz" if n % 5 == 0
labels << "bazz" if n % 7 == 0
puts labels.empty? ? n : labels.join
end
end
fizzbuzz(105)</code></pre>