🪄

JS と Elixir の比較: if...else 文と if マクロ (3)

2024/12/04に公開

前回の記事の続き(最終回)です。JavaScript の if...else 文と Elixir の if マクロを比較します。

JavaScript の if...else 文は基本的な構文は次の通りです。

if (条件式) {
  A
} else {
  B
}

しかし、A と B に単一の文しか含まれない時、中括弧は省略可能です。

if (条件式)
  A
else
  B

Elixir の if マクロ にも類似の省略記法が存在します。

if 条件式,
  do: A,
  else: B

一行で書くこともできます。

if 条件式, do: A, else: B

これは、初回の記事で触れた JavaScript の条件 (三項) 演算子 によく似ています。

条件式 ? A : B

直前の Elixir プログラムと比較してください。


★ここから先は、Elixir中上級者向けです★

ところで、Elixir にはパイプ演算子という面白い書き方があります。

次の例をご覧ください。

x = "red green blue"
x = String.split(x, " ")
x = Enum.map(x, &String.capitalize/1)
x = Enum.join(x, "-")
IO.puts(x)

このプログラムでは、変数 x にセットした文字列をバケツリレー式にさまざまな関数で次々と変換していきます。最終的に変数 x には "Red-Green-Blue" という文字列がセットされます。

登場する関数の役割は次のとおりです:

パイプ演算子 |> を用いると、このプログラムを次のように書き換えることができます。

x =
  "red green blue"
  |> String.split(" ")
  |> Enum.map(&String.capitalize/1)
  |> Enum.join("-")

IO.puts(x)

パイプ演算子 |> の右辺にある関数は、左辺から渡される値を第 1 引数として受け取ります。


さて、パイプ演算子を使わないバージョンのプログラムを次のように書き換えます。

x = "red green blue"
x = String.split(x, " ")
x = if length(x) < 5, do: ["black" | x], else: x
x = Enum.map(x, &String.capitalize/1)
x = Enum.join(x, "-")
IO.puts(x)

3 行目で、変数 x にセットされれているリストの要素数が 5 より小さいとき、リストの先頭に "black" という要素を加えています。変数 list にリストがセットされている時、[e | list] と書くとリストの先頭に e を加えたリストが返ってきます。

このプログラムをパイプ演算子 |> を用いた形に書き換えるにはどうすればよいでしょうか。if マクロは変換の対象を第1引数として取らないので不可能のように見えますが、関数 then/2 を利用するとうまく行きます。

x =
  "red green blue"
  |> String.split(" ")
  |> then(fn x -> if length(x) < 5, do: ["black" | x], else: x end)
  |> Enum.map(&String.capitalize/1)
  |> Enum.join("-")

IO.puts(x)

関数 then/2 は、第 1 引数に任意の値、第 2 引数に無名関数を取ります。そして、第 1 引数を無名関数に渡してその結果を返します。

ごちゃごちゃして読みにくいと感じた方は、次のように書き換えてみてください。

x =
  "red green blue"
  |> String.split(" ")
  |> then(fn x ->
    if length(x) < 5 do
      ["black" | x]
    else
      x
    end
  end)
  |> Enum.map(&String.capitalize/1)
  |> Enum.join("-")

IO.puts(x)

Discussion