Fizz Buzz
Fizz Buzz とは
Fizz Buzz は言葉遊びだ。どのような遊びかと言うと、
プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。ただし、3で割り切れる場合は「Fizz」(Bizz Buzzの場合は「Bizz」)、5で割り切れる場合は「Buzz」、両者で割り切れる場合(すなわち15で割り切れる場合)は「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。(Wikipedia より)
Jeff Atwood はこの言葉遊びをプログラムの問題として、プログラマのセンスを見分けるためにつかったということだ。
Fizz Buzzの Haskell プログラム
そこで、Fizz Buzz に Haskell で挑戦してみた。
ファイル名: fizzbuzz.hs
fizzbuzz n | n `mod` 15 == 0 = "FizzBuzz" | n `mod` 3 == 0 = "Fizz" | n `mod` 5 == 0 = "Buzz" | otherwise = show n
main = mapM_ putStrLn $ map fizzbuzz [1..100]実行例
~/sed$ runghc fizzbuzz.hs 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 以下略
State モナドを使った FizzBuzz
State モナドを使って Fizz Buzz を書いてみた。関数 fizz は3の倍数のとき "Fizz" を返し、buzz 関数は5の倍数のとき "Buzz" を返す。FizzBuzz 関数はないが、15の倍数のときは、"Fizz" と "Buzz" がマージされて "FizzBuzz" が出力される。State モナドを使ったのは、関数 fizz と関数 Buzz の結合を >>= 演算子でやりたかったからだ。ファイル名: fizzbuzz.hs
import Control.Monad.State
fizz :: String -> State Int String fizz str = do n <- get if mod n 3 == 0 then return (str ++ "Fizz") else return (str ++ "") buzz :: String -> State Int String buzz str = do n <- get if mod n 5 == 0 then return (str ++ "Buzz") else return (str ++ "") fizzbuzz n = let (str,m) = runState (return [] >>= fizz >>= buzz) n in case str of [] -> show m _ -> str
main = mapM_ putStrLn $ map fizzbuzz [1..100]
モジュール化 Fizz Buzz
上のプログラムでは fizz と buzz の定義が繰り返しになったのでモジュール化してみた。プログラムの都合で上のプログラムとは違って、状態を文字列にして、リターン値を整数にした。fizz 関数と buzz 関数は maker 関数の部分適用で得られる。
import Control.Monad.State
maker :: String -> Int -> Int -> State String Int maker str m n = do stack <- get if mod n m == 0 then put (stack ++ str) else put (stack ++ "") return n
fizz = maker "Fizz" 3 buzz = maker "Buzz" 5
fizzbuzz n = let (m, str) = runState (return n >>= fizz >>= buzz) [] in case str of [] -> show m _ -> str
main = mapM_ putStrLn $ map fizzbuzz [1..100]