HaskellでFizzBuzz

  • 11
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

Haskellを勉強中で無性に、腐るほどあるFizzBuzz(関数)が書きたくなった。

fizzbuzz :: Integer -> [String] 
fizzbuzz 0 = []
fizzbuzz n
    | n `mod` 15 == 0 = fizzbuzz(n - 1) ++ ["fizzbuzz"]
    | n `mod` 3 == 0 = fizzbuzz(n - 1) ++ ["fizz"]
    | n `mod` 5 == 0 = fizzbuzz(n - 1) ++ ["buzz"]
fizzbuzz n = fizzbuzz(n - 1) ++ [show n]

間違っているかもしれない解説

fizzbuzz :: Integer -> [String] 

はfizzbuzz関数の型宣言。これはInteger型を引数にしてStringの配列を返すという意味。これは書かなくても推論してくれるらしいがすごいH本によると書いたほうがいいらしい。

fizzbuzz 0 = []

fizzbuzz 0が来たら、

fizzbuzz n
    | n `mod` 15 == 0 = fizzbuzz(n - 1) ++ ["fizzbuzz"]
    | n `mod` 3 == 0 = fizzbuzz(n - 1) ++ ["fizz"]
    | n `mod` 5 == 0 = fizzbuzz(n - 1) ++ ["buzz"]

は15か3か5で割れるかのガードで

fizzbuzz n = fizzbuzz(n - 1) ++ [show n]

はこぼれたやつ。

この関数は再帰的に呼ばれるので、例えばfizzbuzz 3とすると、
fizzbuzz 3 -> fizzbuzz(2) ++ ["fizz"] -> fizzbuzz(1) ++ ["2", "fizz"] -> fizzbuzz(0) ++ ["1", "2", "fizz"]->["1", "2", "fizz"]
となる(はず)。

呼ばれる順に詳しく見ていく

fizzbuzz n
    | n `mod` 15 == 0 = fizzbuzz(n - 1) ++ ["fizzbuzz"]
    | n `mod` 3 == 0 = fizzbuzz(n - 1) ++ ["fizz"]
    | n `mod` 5 == 0 = fizzbuzz(n - 1) ++ ["buzz"]

はガードと呼ばれるもので、nがなんの倍数か判定している。それがわかったらfizzbuzz(n -1)と対応する文字列をくっつけて返す。"fizzbuzz" : fizzbuzz(n - 1)としたくなるが(自分だけ?)、これだと結果が逆になってしまう。

fizzbuzz n = fizzbuzz(n - 1) ++ [show n]

は上のガードからこぼれたら来るもので、こちらはshow nInteger -> Stringしている。

fizzbuzz 0 = []

は最後なので空の配列を返して終了

fizzbuzz 100

*Main> fizzbuzz 100
["1","2","fizz","4","buzz","fizz","7","8","fizz","buzz","11","fizz","13","14","fizzbuzz","16","17","fizz","19","buzz","fizz","22","23","fizz","buzz","26","fizz","28","29","fizzbuzz","31","32","fizz","34","buzz","fizz","37","38","fizz","buzz","41","fizz","43","44","fizzbuzz","46","47","fizz","49","buzz","fizz","52","53","fizz","buzz","56","fizz","58","59","fizzbuzz","61","62","fizz","64","buzz","fizz","67","68","fizz","buzz","71","fizz","73","74","fizzbuzz","76","77","fizz","79","buzz","fizz","82","83","fizz","buzz","86","fizz","88","89","fizzbuzz","91","92","fizz","94","buzz","fizz","97","98","fizz","buzz"]