This code solves the problem of FizzBuzz. Is it possible in any way to improve it?
main = main' 1 where
main' n = do
(putStrLn . choose) (show n, "Fizz", "Buzz", "FizzBuzz", n)
if n < 100 then main' (succ n) else putStrLn "End!"
where
choose (n0, n3, n5, n15, n)
| mod n 3 == 0 && mod n 5 == 0 = n15
| mod n 5 == 0 = n5
| mod n 3 == 0 = n3
| True = n0
-
\$\begingroup\$ Which definition of FizzBuzz are you using? Based on the first Google result the #s are fixed at [1..100], so there shouldn't be any inputs. \$\endgroup\$jnewman– jnewman2012年11月24日 19:33:28 +00:00Commented Nov 24, 2012 at 19:33
3 Answers 3
You could separate your I/O from the pure code:
fizzBuzz :: Int -> String
fizzBuzz n | mod n 3 == 0 && mod n 5 == 0 = "FizzBuzz"
| mod n 5 == 0 = "Buzz"
| mod n 3 == 0 = "Fizz"
| otherwise = show n
main = mapM print (map fizzBuzz [0..100])
-
5\$\begingroup\$ I think
mapM (print . fizzBuzz) [0..100]
would be better. \$\endgroup\$Komi Golov– Komi Golov2012年11月24日 21:08:31 +00:00Commented Nov 24, 2012 at 21:08 -
3\$\begingroup\$
mapM_
would be even better. \$\endgroup\$hammar– hammar2012年11月25日 13:44:22 +00:00Commented Nov 25, 2012 at 13:44
jaket is definitely right, the pure/impure distinction is important. My addition would be that you should avoid recomputing the modulo:
fizzBuzz :: Int -> String
fizzBuzz n | fizz && buzz = "FizzBuzz"
| buzz = "Buzz"
| fizz = "Fizz"
| otherwise = show n
where fizz = mod n 3 == 0
buzz = mod n 5 == 0
sfb = map fizzBuzz [1..15]
I had written something similar to Will, but the spec I read here says, that FizzBuzz should always cover [1..100], so my implementation was a bit different:
show' :: Int -> String
show' n
| fizz && buzz = "FizzBuzz"
| buzz = "Buzz"
| fizz = "Fizz"
| otherwise = show n
where fizz = mod n 3 == 0
buzz = mod n 5 == 0
fizzBuzz = [show' x | x <- [1..100]]
Will's idea about using where to cache the mod result was a nice idea IMHO.