ElixirでFizzBuzzを書いてみた

2022/05/23に公開

Elixir で FizzBuzz を書いてみました。人生の中で今まで書いた FizzBuzz の中では一番苦労しましたが、学びの多い、良い FizzBuzz が書けたと思います。メモ代わりにいろいろ書き留めておきます。当方 Elixir 初心者につき理解が怪しいところがあると思いますので、その点はご容赦ください。

環境構築

「Elixir 実践ガイド」(黒田(2021))を参考に Elixir の環境構築を行いました。本書は環境構築に Docker / Docker Compose を用いていますので、本書と Docker のドキュメントを参考に、Docker を用いて環境を構築しました。Docker にはそれほど慣れておりませんでしたが、持ち前のガッツと明るさで乗り切りました。

FizzBuzz モジュール

以下の FizzBuzz モジュールに FizzBuzz を返す関数 fb を実装します。

defmodule FizzBuzz do
  @moduledoc """
  Module to run FizzBuzz.
  """

  @doc """
  returns "FizzBuzz" if `n` is divisible by both three and five,
  returns "Fizz" if `n` is divisible by three,
  returns "Buzz" if `n` is divisible by five,
  else returns `n`.
  """
  def fb(n) when rem(n, 15) == 0, do: "FizzBuzz"
  def fb(n) when rem(n, 3) == 0, do: "Fizz"
  def fb(n) when rem(n, 5) == 0, do: "Buzz"
  def fb(n), do: n
end

defmodule でモジュールを定義しています。 @moduledoc@docモジュール属性です。Elixir におけるドキュメンテーションコメントといったところでしょうか。今回のコードでは活用できていませんが、Markdown で書けます。

肝心の処理は、関数 fb の引数に対するパターンマッチングで FizzBuzz を返しています。関数については

def fb(n) do
  # TODO
end

のような形式でも書くことができますが、いわゆるキーワード形式と呼ばれる、上記のような( , do: "FizzBuzz" )書き方もできます。詳しくは黒田(2021) p.121 を参照してください。

パイプ演算子

上記 FizzBuzz モジュールの fb 関数を用いて、FizzBuzz を標準出力に出力します。Elixir らしく(要出典)、パイプ演算子を用います。

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

Elixir の Enum#map 関数は、enumerable と fun の 2 つの引数をとります(参考文献 5)。それにも関わらず、上記のコードの 2 行目では引数を 1 つしか受け取っていません。パイプ演算子の右側に置かれた関数は、第 1 引数をパイプ演算子の左側の式から受け取ります。そのため、2 行目では enumerable として Range 構造体 1..100 を受け取っています。

1..100 を受け取った Enum#map 関数は、 1..100 のそれぞれについて FizzBuzz#fb を呼び出します。ここで、 &FizzBuzz.fb/1& は、名前付き関数を関数型の 項(term) として取り出す キャプチャ演算子 です。ここでの処理は、FizzBuzz#fb 関数を引数として渡している、ということです。また &FizzBuzz.fb/1/1 は引数の個数を表す アリティ(arity) です。ここでは、引数の数が 1 の関数であることを表しています。

FizzBuzz#fb の評価結果をさらにパイプ演算子の右項に渡しています。ここはちょっと説明を誤魔化しますが、enumerable のそれぞれの項を引数として IO#puts を呼び出しています。

これで FizzBuzz ができました。FizzBuzz をするだけで一苦労でしたが、とてもきれいなコードが書けたのではないかと思います。もうしばらく、Elixir と戯れてみたいです。

GitHub のリポジトリ

GitHub のリポジトリとしてソースコードを公開しました。

Reference

  1. 黒田勉、(2021)、Elixir 実践ガイド、インプレス
  2. 大澤文孝、浅居尚、(2020)、docker 基礎からのコンテナ構築、日経 BP
  3. Install Docker Engine on Ubuntu、retrieved from https://docs.docker.com/engine/install/ubuntu/(最終アクセス日:2022年5月23日)
  4. Docker Compose のインストール、retrieved from https://docs.docker.jp/compose/install.html(最終アクセス日:2022年5月23日)
  5. Enum#map、retrieved from https://hexdocs.pm/elixir/1.12/Enum.html#map/2(最終アクセス日:2022年5月23日)
  6. Enum#puts、retrieved from https://hexdocs.pm/elixir/IO.html#puts/2(最終アクセス日:2022年5月23日)

Discussion