« 柔軟な発想 | トップページ | Haskell の配列 »

2011年12月 1日 (木)

またまた「FizzBuzz」

 かなり久しぶりのブログ更新です。
 最近、また「FizzBuzz問題」が気になりまして……。

 

 一般的な「FizzBuzz問題」といえばこちらのルールですよね。
 Haskell だとこんな感じでしょうか?

fizzbuzz :: [String] fizzbuzz = map f [1 .. ] where f x | rem x 15 == 0 = "FizzBuzz" | rem x 3 == 0 = "Fizz" | rem x 5 == 0 = "Buzz" | otherwise = show x main :: IO () main = putStr $ unlines $ take 100 fizzbuzz

 

 そういえば、「剰余関数を使わない」という制限を加えたものもありましたね。ネット上では次のようなコードが有名(?)だったと思います。

fizzbuzz :: [String] fizzbuzz = zipWith f [1 .. ] $ zipWith (++) fizz buzz where f x "" = show x f _ y = y fizz = cycle ["", "", "Fizz"] buzz = cycle ["", "", "", "", "Buzz"] main :: IO () main = putStr $ unlines $ take 100 fizzbuzz

 

 この方法とは別に、リストの要素に n 個置きに関数を適用する step 関数を Haskell で定義すると、「剰余関数を使わない」で FizzBuzz ができます。

-- リストの先頭から n 個目ごとに f を適用 -- ex : step 3 (\x -> 0) [1 .. 10] => [0,2,3,0,5,6,0,8,9,0] step :: Int -> (a -> a) -> [a] -> [a] step _ _ [] = [] step n f xs = f a : as ++ step n f bs where (a : as, bs) = splitAt n xs fizzbuzz :: [String] fizzbuzz = tail $ foldl conv ss factors where ss = map show [0 ..] factors = [(3, "Fizz"), (5, "Buzz"), (15, "FizzBuzz")] conv ss (a, b) = step a (\ x -> b) ss main :: IO () main = putStrLn $ unlines $ take 100 fizzbuzz

 初めのうちは、ss = map show [0 .. 100] としていたのですが、試しに無限数列にしてみたら、ちゃんと動きました。
 なぜちゃんと動くかが自分でも分っていないのですが、遅延評価ってすごいなぁと思います。

 

 さて、ここからが本題なのですが、「3 と 5 意外の数で FizzBuzz してもいいじゃないか」ということで、任意の数の倍数を任意の文字列で置き換える「拡張版 FizzBuzz」を考えてみました。

{- 任意の数と文字列を指定できる FizzBuzz -} import System.Environment (getArgs) -- ex : fizzbuzz [(2, "Fizz"), (3, "Buzz")] -- -> ["1","Fizz","Buzz","Fizz","5","FizzBuzz","7","Fizz" ..] fizzbuzz :: [(Int, String)] -> [String] fizzbuzz xs = map f [1 ..] where f n = if null str then show n else str where str = foldr g [] xs g (x, cs) tmp = if rem n x == 0 then cs ++ tmp else tmp -- ex : fizzbuzz 100 3 fizz 5 buzz main :: IO () main = do args <- getArgs let n = read (head args) xs = format (tail args) in mapM_ putStrLn $ take n $ fizzbuzz xs where format [] = [] format (n : x : xs) = (read n, x) : format xs

 実行結果は次のようになります。

$ runghc fizzbuzz8.hs 50 2 Fizz 3 Buzz 5 Bar 1 Fizz Buzz Fizz Bar FizzBuzz 7 Fizz Buzz FizzBar 11 FizzBuzz 13 Fizz BuzzBar Fizz 17 FizzBuzz 19 FizzBar Buzz Fizz 23 FizzBuzz Bar Fizz Buzz Fizz 29 FizzBuzzBar 31 Fizz Buzz Fizz Bar FizzBuzz 37 Fizz Buzz FizzBar 41 FizzBuzz 43 Fizz BuzzBar Fizz 47 FizzBuzz 49 FizzBar

« 柔軟な発想 | トップページ | Haskell の配列 »

Haskell」カテゴリの記事

コメント

コメントを書く

コメントは記事投稿者が公開するまで表示されません。

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/112020/53378056

この記事へのトラックバック一覧です: またまた「FizzBuzz」:

« 柔軟な発想 | トップページ | Haskell の配列 »

2016年7月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
フォト

最近のトラックバック

無料ブログはココログ