Functional FizzBuzz

There was a discussion that was resurrected on programmers.stackexchange yesterday talking about FizzBuzz. First things first: the only thing I’d accept on FizzBuzz is minor syntax errors. It appears from the aforementioned discussion that I might be holding a minority opinion. Given that, I started to wonder what FizzBuzz would look like if written in an idiomatic functional style (while not necessarily purely functional) and if my functional FizzBuzz would convince someone else that I was a competent functional developer, even if I don’t consider myself one.

I’m coming off a vacation, and have decided to blog more in the coming year, so I decided to settle into 2014 and combine the two. True to FizzBuzz form I wrote a solution in F# without testing it. I did use an IDE, though. Either way, this is what I came up with:

let numbers =
    seq { 1 .. 100 }
    |> Seq.mapi (fun i n -> (i, n % 3 = 0, n % 5 = 0))
    |> Seq.map (fun t ->
    match t with
        | (_, true, true) ->"FizzBuzz"
        | (_, true, false) -> "Fizz"
        | (_, false, true) -> "Buzz"
        | (n, false, false) -> n.ToString()
        )

numbers
    |> Seq.map (fun s -> printfn "%A" s)
    |> ignore

Clearly, it’s wrong. There’s no output whatsoever. Things aren’t looking good for me.

I quickly realize that numbers is lazily evaluated, and when I Seq.map it to a function that writes to the console (ie. no return value), without actually accessing any value in the collection, the whole Seq.map is being optimized out. Ok use Seq.iter over numbers.

So I run it again and find that the output starts at zero and all of the Fizz/Buzz statements are off by 1, but otherwise appear correct. Seeing the output on screen, it appear obvious: I don’t need the index from Seq.mapi… I already have it from the sequence. Not only is Seq.mapi redundant here, it’s also zero based when my sequence starts at 1. A normal Seq.map is clearly better.

With that done, I ran it again and found that it works as desired. The result is thus:

let numbers =
    seq { 1 .. 100 }
    |> Seq.map (fun n -> (n, n % 3 = 0, n % 5 = 0))
    |> Seq.map (fun t ->
    match t with
        | (_, true, true) -> "FizzBuzz"
        | (_, true, false) -> "Fizz"
        | (_, false, true) -> "Buzz"
        | (i, _, _) -> i.ToString()
        )

numbers
    |> Seq.iter (fun s -> printfn "%A" s)
    |> ignore

Note: the first/redundant map was left for (my) clarity. It can be removed and replaced by changing the match to: match (n, n % 3 = 0, n % 5 = 0)

That’s it; total time was 10 minutes. As I said, I clearly wouldn’t hire me as a developer in a functional language, but would someone else?

Advertisements