FizzBuzz in Elixir

昨日まで約一週間、↓このサイトの GETTING STARTED をやってきた。

 cf. Elixir

1 ~ 20 までのちょうど半分、10 までやったので、ここでちょっと気分を変えて、自分でスクリプトを書いてみよう。お題は定番の FizzBuzz 問題だ。

まず最初に書いたのがこれ:

defmodule FizzBuzz do

  def fizzbuzz(n) when rem(n, 15) == 0 do
    "FizzBuzz"
  end

  def fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  def fizzbuzz(n) when rem(n, 5) == 0 do
    "Buzz"
  end

  def fizzbuzz(n) do
    to_string(n)
  end

  def fizzbuzz_iter(n) when n >= 100 do
    IO.puts(fizzbuzz(n))
  end

  def fizzbuzz_iter(n) do
    IO.puts(fizzbuzz(n))
    fizzbuzz_iter(n + 1)
  end

end

FizzBuzz.fizzbuzz_iter(1)

実行例は示さないけど、ちゃんと期待通りに動いた。動いたんだけど、なんというかコードがすごく冗長。関数定義が複数の句を持てるのはいいけど、これはちょっと醜いな。

で、以前 Haskell でやった剰余を使わない方法でやってみた。

defmodule FizzBuzz do

  def fb(x) do
    case x do
      {{_, "Fizz"}, "Buzz"} -> "FizzBuzz\n"
      {{_, "Fizz"}, ""} -> "Fizz\n"
      {{_, ""}, "Buzz"} -> "Buzz\n"
      {{m, ""}, ""} -> "#{to_string(m)}\n"
    end
  end

  def fizzbuzz() do
    fizz = Stream.cycle(["", "", "Fizz"])
    buzz = Stream.cycle(["", "", "", "", "Buzz"])
    1..100 |> Enum.zip(fizz) |> Enum.zip(buzz) |> Enum.map(&fb/1)
  end

end

FizzBuzz.fizzbuzz() |> IO.puts

だいぶすっきりしたけど、ネストしたタプルがあんまりよくないな。あ、出力用の文字列にいちいち改行文字がついてるのは、こうしないと全部つながって出力されるから。リストをパイプで IO.puts に渡すと、全要素を出力してから改行するらしい。そんなわけで1つ余計に改行が出力されることになったんだけど、それはまあ、いいことにする。

もう少し改良してみよう。case でパターンマッチさせるなら、何もパイプを使わずに n35 で割った余り(とn)でパターンマッチすればいい。

defmodule FizzBuzz do

  def fizzbuzz(n) do
    case {rem(n, 3), rem(n, 5), n} do
      {0, 0, _} -> "FizzBuzz\n"
      {0, _, _} -> "Fizz\n"
      {_, 0, _} -> "Buzz\n"
      {_, _, m} -> "#{to_string(m)}\n"
    end
  end

end

1..100 |> Enum.map(&FizzBuzz.fizzbuzz/1) |> IO.puts

良くなった。パターンマッチもきれいだし、いいんじゃないかな。

[追記]

Enum.each/2 を覚えた!

defmodule FizzBuzz do

  def fizzbuzz(n) do
    case {rem(n, 3), rem(n, 5), n} do
      {0, 0, _} -> "FizzBuzz"
      {0, _, _} -> "Fizz"
      {_, 0, _} -> "Buzz"
      {_, _, m} -> to_string(m)
    end
  end

end

1..100
|> Enum.map(&FizzBuzz.fizzbuzz/1)
|> Enum.each(&IO.puts/1)

これで余計な改行もなくなってきれいになった。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください