A Quick Exercise

Let’s see how much Haskell you can understand just by first grasping an informal, hand-wavy solution and then looking at the corresponding code. It’s very much a “think in data” solution, but also probably quite different from how you’ve seen this kind of problem approached before. Without modulo division or if statements, I give you “Functional Fizz Buzz.”

The task is this: you want Fizz every three steps, and Buzz every five steps. We note that sometimes the cycles coincide. Let’s talk cycles then.

 threes = cycle ["", "", "Fizz"]
 fives = cycle ["", "", "", "", "Buzz"]

cycle is defined like this (the real library def is more efficient, but less clear):

 cycle xs = xs ++ cycle xs -- SIMPLE version of lib

So threes just spits out ["","","Fizz","","","Fizz",... ] until we stop it, and similarly for fives. Next, we want to merge two streams into one: this is quite common, so there’s a library function for it. zipWith pairs up elements and uses some operation to combine each pair:

 zipWith g [a,b,c,...] [d,e,f, ...] ===>
  (computes to) [g a d, g b e, g c f, ...]
 eg zipWith max [1,2,3] [2,2,2] ===> [2,2,3]
 eg zipWith (*) [1,2,3] [2,2,2] ===> [2,4,6]

Think zippers in clothes. Now, that’s just what we want for merging our streams. It works for infinite streams too (why shouldn’t it?).

 fizzbuzz = zipWith (++) threes fives

(++) is string concatenation, and then we just push the list of lines to the screen. And hit ^C when we get bored.

 main = putStr (unlines fizzbuzz)

If we want numbers in there between the Fizzes and Buzzes instead of blanks, we can just zip in another list that contains the numbers from 1 up to infinity, and just add in a number if the string would otherwise be empty.

So, it’s a short piece of code that obviously works, built from small pieces and glued together in a simple way (think Unix pipes), and there’s no worry about loops, division, variables, memory limits...

This isn’t a one-off trick. Programming with Haskell is generally like this.