So here’s mine

I’m sure someone has already thought of this but, I’m too lazy to search around and see.

Almost FizzBuzz

I’m going to view the output of a fizzbuzz implementation as a list. Observation: once you know the position of the Fizzes, Buzzes and FizzBuzzes in the first 15 items in the list you know their position the entire list. So for example Fizz occurs at 3, but also at 18, 33, 48, … 99. So if we create a fizzbuzz list of length 15, we can create a list of length 30 just by appending the list to itself. In a lazy language like haskell we may as well create an inifinite list since it doesn’t cost us anything until we take the finite list of the size we want, 100.

-- For those not familiar with haskell syntax, the <$> is an infix
-- version of map, cycle repeats the list an infinite number
-- of times, and take n grabs the first n elements.
almostFizzbuzz n = take n . cycle $ fb <$> [1..15]
  where
    fb n
      | n == 15        = "FizzBuzz"
      | n `mod` 3 == 0 = "Fizz"
      | n `mod` 5 == 0 = "Buzz"
      | otherwise      = show n

What I like about this is that we don’t have to check for numbers that are both Fizz and Buzz, since we know that the only number that requires FizzBuzz in the first 15 is 15 itself. It turns out that we only need to call the modulo operator 24 times no matter how big n is!

This almost works but there is one problem, the numbers in the list are wrong after position 15, they just repeat themselves. So almostFizzbuzz 100 begins:

[ "1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11"
, "Fizz","13","14","FizzBuzz", "1","2","Fizz","4", ...
]

We’re close, but not quite there.

FizzBuzz

The solution is straightforward, instead of creating an infinite list of strings, we create an infinite list of functions with integer arguments that are constant on all of the Fizzes, Buzzes, and FizzBuzzes and shows the integer elsewhere. Then we simply apply these functions to a list of all integers starting at 1.

-- Here zipWith ($) applies the functions in the list int2fb to the
-- list of integers from 1 to infinity. And const "some string" is a function
-- that returns "some string" regardless of it's argument.
fizzbuzz n = take n $ zipWith ($) int2fb [1..]
  where
    int2fb = cycle $ fb <$> [1..15]
    fb n
      | n == 15        = const "FizzBuzz"
      | n `mod` 3 == 0 = const "Fizz"
      | n `mod` 5 == 0 = const "Buzz"
      | otherwise      = show

Still only 24 calls to mod, yay!