Haskellの書き方も何となくわかってきたので、ここで基本に立ち返り、いわゆるFizzBuzz問題をHaskellで実装してみることにする。
FizzBuzz問題の詳細はWikipediaでも見てもらうことにする。要旨を説明すると、FizzBuzz問題は数値を順に表示するが、その際に3の倍数はFizz、5の倍数はBuzz、3の倍数かつ5の倍数はFizz Buzzに置き換えて表示するという問題だ。
FizzBuzz問題をRubyで実装すると以下のコードとなる。fizzbuzz
は整数を取り、それを”Fizz”か”Buzz”か”Fizz Buzz”か数値に変換する。fizzbuzz_map
はArrayで渡された数値列にfizzbuzz
を適用した結果のArrayを返す。
def fizzbuzz(x)
if x % 15 == 0
"Fizz Buzz"
elsif x % 3 == 0
"Fizz"
elsif x % 5 == 0
"Buzz"
else
x.to_s
end
end
def fizzbuzz_map(xs)
xs.map{|x|
fizzbuzz x
}
end
p fizzbuzz_map [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
# => ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "Fizz Buzz"]
これをHaskellで実装してみることにする。Haskellで分岐を実現する方法はif then else
やパターンマッチなどいくつか方法があるが、今回はガード式でfizzbuzz
を実装することにする。fizzbuzz_map
はリストの整数に順にfizzbuzz
を適用するものとし、リストから順に値を取り出すのにリスト内包表記のジェネレータを利用する。便宜的にこの内容をfizzbuzz.hs
に保存してあるものとする。
fizzbuzz :: Int -> String
fizzbuzz x
| x `mod` 15 == 0 = "Fizz Buzz"
| x `mod` 3 == 0 = "Fizz"
| x `mod` 5 == 0 = "Buzz"
| otherwise = show x
fizzbuzz_map :: [Int] -> [String]
fizzbuzz_map xs = [fizzbuzz x | x <- xs]
これをGHCiからロードして、実行させてみよう。Haskellではfizzbuzz_map
に渡すリストは範囲指定により簡潔に記述できる。
Prelude> :l fizzbuzz.hs
[1 of 1] Compiling Main ( fizzbuzz.hs, interpreted )
Ok, modules loaded: Main.
*Main> fizzbuzz_map [1..15]
["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","Fizz Buzz"]
なお敢えてfizzbuzz
とfizzbuzz_map
を別の定義にしているが、fizzbuzz
がfizzbuzz_map
だけからしか呼び出されない局所関数でも良いなら、where
を使って以下の書き方もできる。
fizzbuzz_map :: [Int] -> [String]
fizzbuzz_map xs = [fizzbuzz x | x <- xs]
where fizzbuzz x
| x `mod` 15 == 0 = "Fizz Buzz"
| x `mod` 3 == 0 = "Fizz"
| x `mod` 5 == 0 = "Buzz"
| otherwise = show x
FizzBuzzの実装とは関係ないが、Haskellの入門には”すごいHaskellたのしく学ぼう!”がおすすめだ。これを読み進めるとみるみるHaskellでコードを書けるようになる。
オーム社
売り上げランキング: 126,678