Hatena::Groupbugrammer

蟲!虫!蟲!

Esehara Profile Site (by Heroku) / Github / bookable.jp (My Service)
過去の記事一覧はこちら

なにかあったら「えせはら あっと Gmail」まで送って頂ければ幸いです。
株式会社マリーチでは、Pythonやdjango、また自然言語処理を使ったお仕事を探しています

 | 

2011-10-12

[] HaskellにおけるFizzBuzzの考察 22:13

 まだFizzBuzzかよ、的な話なんだけど、個人的にHaskellFizzBuzzが面白かったので。あと、HaskellFizzBuzzを書こうとしたら、いまいち上手く出来なかったので、復習もかねて。

 Pythonで"if"を使わない"FizzBuzzチェック関数"を三種類ほど実装する - 蟲!虫!蟲! - #!/usr/bin/bugrammer という趣旨のFizzBuzz話を書いたときに、ifやforを使うのって、手続型言語の場合が多く、では関数型言語だとどうなるか、という話でもある。HaskellにはいわゆるIF相当のものは存在しているけれども、"for"は存在していない。もし繰り返したければ、個別にリストを作ってやって、それに適用する、というのが基本的な方針っぽい。

 なので、素直に書けば、下のように書ける。

fizzbuzz::Integer -> String
fizzbuzz x
    | (x `mod` 3 == 0) && (x `mod` 5 == 0) = "fizzbuzz"
    | (x `mod` 3 == 0) = "fizz"
    | (x `mod` 5 == 0) = "buzz"
    | otherwise = show x

main :: IO()
main = putStrLn $ show $ map fizzbuzz [1..100]

 Haskellだと、引数と返すものの型は一緒じゃないといけないので、show関数でxを文字列にして整える。

 あとは、パターンマッチを使うという手もある。

fizzbuzz :: Integer -> String
fizzbuzz x = is_fizzbuzz (x `mod` 3) (x `mod` 5) x

is_fizzbuzz :: Integer -> Integer -> Integer -> String
is_fizzbuzz 0 0 _ = "fizzbuzz"
is_fizzbuzz 0 _ _ = "fizz"
is_fizzbuzz _ 0 _ = "buzz"
is_fizzbuzz _ _ x = show x

main :: IO()
main = putStrLn $ show $ map fizzbuzz [1..100]

 パターンマッチを使うのはちょっと冗長な気もする。

 あとは、前にも書いた、配列の利用というのもある。

fizz = ["fizz","",""]
buzz = ["buzz","","","",""]

list_fizzbuzz :: Int -> [String] -> Int -> String
list_fizzbuzz x y z = (foldr (++) [] $ replicate (x + 1) y) !! z

is_fizzbuzz :: Int -> String
is_fizzbuzz x = list_fizzbuzz (div x 3 :: Int) fizz x ++ list_fizzbuzz (div x 5 :: Int) buzz x

fizzbuzz :: Int -> String
fizzbuzz x
    | is_fizzbuzz x == "" = show x
    | otherwise = is_fizzbuzz x

main :: IO()
main = putStrLn $ show $ map fizzbuzz [1..100]

 もう少し頑張れば割り算も削れる気がするが省略。

 あと、少し丁寧に書くと、こういう感じかなあ。

fizzbuzz::Integer -> String
fizzbuzz x
    | is_fizzbuzz x == "" = show x
    | otherwise = is_fizzbuzz x

fb::Integer -> String -> Integer -> String
fb y z x
    | (x `mod` y) == 0 = z
    | otherwise = ""

is_fizzbuzz :: Integer -> String
is_fizzbuzz x = fb 3 "fizz" x ++ fb 5 "buzz" x

main :: IO()
main = putStrLn $ show $ map fizzbuzz [1..100]

あわせ技だと、これが一番綺麗のような気がするな。

no title

 |