HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Haskell FizzBuzz with a type system

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withsystemfizzbuzztypehaskell

Problem

The core problem is simple enough, but I've developed a type system that I'm not sure about. The intention is, if the result is a number, calling num $ fizzBuzz 16, for example, lets me retrieve 16 as an Int. However, it seems awfully repetitive, to have to mention "Fizz" so many times in the code. Can it be done better?

data NoiseNum = Fizz | Buzz | FizzBuzz | Num Int
  deriving (Eq)

instance Show NoiseNum where
  show FizzBuzz = "FizzBuzz"
  show Fizz     = "Fizz"
  show Buzz     = "Buzz"
  show (Num n)  = show n

num :: NoiseNum -> Int
num (Num n) = n

fizzBuzz :: Int -> NoiseNum
fizzBuzz n
  | n `mod` 15 == 0 = FizzBuzz
  | n `mod`  3 == 0 = Fizz
  | n `mod`  5 == 0 = Buzz
  | otherwise       = Num n

main = do
  mapM_ putStrLn $ map (show . fizzBuzz) [1..100]

Solution

In the issue 23 of The Monad.Reader, there is a nice discussion of FizzBuzz and how to solve it efficiently in Haskell. The efficiency being in terms of future extensions such as "output Bazz if it's a multiple of 7, FizzBazz if it's a multiple of 21, (...)". The proposed solution is linear in the number of conditions.

The final answer goes something like this (but I'd advise you to go through the paper: it's a pretty nice read!):

fizzbuzz n = (test 3 "Fizz" . test 5 "Buzz") id (show n)
  where test d s x | n `mod` d == 0 = const (s ++ x "")
                   | otherwise = x

Code Snippets

fizzbuzz n = (test 3 "Fizz" . test 5 "Buzz") id (show n)
  where test d s x | n `mod` d == 0 = const (s ++ x "")
                   | otherwise = x

Context

StackExchange Code Review Q#56901, answer score: 3

Revisions (0)

No revisions yet.