exp777.hatenablog.com

頭の中はゲームでいっぱい

OCamlでFizz Buzz

 今日はOCamlの勉強をした。それで、Fizz Buzzなるプログラミング問題があるらしいので早速OCamlで書いてみた。
 Fizz Buzzは、数字をカウントアップしながら言って、

  • 数字が3の倍数なら、数字の代わりに"Fizz"と言う
  • 5の倍数なら"Buzz"と言う
  • 3の倍数で5の倍数でもあるなら"Fizz Buzz"と言う

というゲームらしい。これ、おもしろいのかなあ?

let fizzbuzz n =
  let rec iter i n =
    if i > n then ()
    else
    if i == 1 then begin
      print_string "1";
      iter 2 n
    end
    else begin
      print_string ", ";
      if i mod 15 == 0 then begin
        print_string "Fizz Buzz";
        iter (i + 1) n
      end
      else
        if i mod 3 == 0 then begin
          print_string "Fizz";
          iter (i + 1) n
        end
        else
          if i mod 5 == 0 then begin
            print_string "Buzz";
            iter (i + 1) n
          end 
          else begin
            print_int i;
            iter (i + 1) n
          end
    end
  in
  iter 1 n;;

fizzbuzz (int_of_string Sys.argv.(1));;
print_string "\n";;
$ ./fizzbuzz 36
1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, Fizz Buzz, 31, 32, Fizz, 34, Buzz, Fizz

 一応作れたんだけど、ダサいコードなので以下のページを参考にして改良。

let rec p x =
  match x with
    [] -> ()
  | x :: [] -> print_string(x ^ "\n")
  | x :: xs -> begin
      print_string(x ^ ", ");
      p xs
    end

let fizzbuzz n =
  let rec iter i ans =
    if i == 0 then ans
    else
      if i mod 15 == 0 then
        iter (i - 1) ("Fizz Buzz" :: ans)
      else
        if i mod 3 == 0 then
          iter (i - 1) ("Fizz" :: ans)
        else
          if i mod 5 == 0 then
            iter (i - 1) ("Buzz" :: ans)
          else
            iter (i - 1) ((string_of_int i) :: ans)
  in iter n [];;

p (fizzbuzz (int_of_string Sys.argv.(1)));;

本当は、fizzbuzz関数を最後に評価して返り値を表示してくれれば良かったんだけど、何も出してくれなかったので表示関数を自作。たぶん車輪の再発明になってる。リストを表示する関数があったら教えてください。
 それにしてもパターンマッチングはかっこいいな!