Fizzbuzz Redux

fizzbuzz

There is an interesting monoid instance for Maybe a types whenever a is a monoid, which ignores Nothing and applies the underlying monoid under the Just. In Fizz-Buzz, Fizz is supposed to appear in place of every third number, and Buzz in place of every fifth number, but both should appear on every fifteenth number. So we can generate a fizzbuzz stream first, and then find a way to combine it with integers. The key is to combine with another monoid structure on Maybe a called the “alternative”, which exists since Maybe is applicative. This latter monoid selects the first Just value that appears in a product, or is Nothing if no such value is found. Zipping the fizzbuzz stream against the list of numbers with the alternative operator <|> gives a list of “just” the preferred values, and then one can safely filter for only the Justs and monadically print the list:

:m +Data.Monoid
:m +Control.Applicative
:m +Data.Maybe
let fizzStream = cycle [Nothing, Nothing, Just "Fizz"]
let buzzStream = cycle [Nothing, Nothing, Nothing, Nothing, Just "Buzz"]
let fizzBuzzStream = zipWith (<>) fizzStream buzzStream

let fizzBuzz = mapM_ putStrLen . catMaybes $ 
               zipWith (<|>) fizzBuzzStream (map (Just . show) [1..100])

What I like about this solution is that it consists entirely of independent, composable pieces, and there is no conditional logic in sight. The monoid structure encodes the conditions of preference. This is certainly not my idea (I think I first heard about it on reddit), but it’s quite slick so I wanted to implement it again myself.