💡

Elixirの無名関数④:パターンマッチング -- YouTube チャンネル daimon.ex 第8回解説

2024/06/06に公開

動画

https://www.youtube.com/watch?v=v8Ry4BFZ-6g

Elixir の 無名関数③:&記法の続きです。

パターンマッチングを利用して無名関数を作る

今回の動画のライブコーディング冒頭で次のような演習問題が提示されました:

【演習問題】次のような仕様の無名関数を作りなさい。

  • 2個の文字列を引数として取る。
  • 2つの引数が両方とも空文字のときは、空文字列を返す。
  • 2つの引数のうち一方が空文字列のときは、他方をそのまま返す。
  • 2つの引数が両方とも空文字でないときは、2つの引数を空白文字1個で連結して返す。

これの意味するところを具体例で示すと次のようになります:

  • """" が与えられたら "" を返す。
  • "ab""" が与えられたら "ab" を返す。
  • """cd" が与えられたら "cd" を返す。
  • "ab""cd" が与えられたら "ab cd" を返す。

パターンマッチングを使わずに作った例がこれです:

fn a, b ->
  if a == "" do
    b
  else
    if b == "" do
      a
    else
      a <> " "  <> b
    end
  end
end

パターンマッチングを使って書き直した例がこちらです:

fn 
  a, "" -> a
  "", b -> b
  a, b -> a <> " " <> b
end

caseマクロとの比較

パターンマッチングを利用して作られた無名関数は case マクロと似ています。次の例をご覧ください:

case {a, b} do 
  {a, ""} -> a
  {"", b} -> b
  {a, b} -> a <> " " <> b
end

タプル {a, b} が与えられ、ab にそれぞれ文字列がセットされているとき、上記の式を評価すると前述の無名関数と同じ結果が得られます。

ただし、case マクロの場合、次のような書き方はできません:

case a, b do
  a, "" -> a
  "", b -> b
  a, b -> a <> " " <> b
end

このコードはコンパイルエラー(undefined function case/3)を引き起こします。

名前付き関数におけるパターンマッチング

動画の中で作成した無名関数を再掲します:

fn 
  a, "" -> a
  "", b -> b
  a, b -> a <> " " <> b
end

これを名前付き関数に変換するとどうなるでしょうか。case マクロを使って次のように書き換えるのは一案です:

def concat(a, b) do
  case {a, b} do 
    {a, ""} -> a
    {"", b} -> b
    {a, b} -> a <> " " <> b
  end
end

しかし、もっとElixirらしい書き方があります:

def concat(a, ""), do: a
def concat("", b), do: b
def concat(a, b), do: a <> " " <> b

Discussion