&>=/2, &<=/2, &</2などなどはFunction capturingです(Elixir)


山里は冬ぞ寂しさまさりける人目も草もかれぬと思へば

Advent Calendar 2022 78日目1の記事です。
I'm looking forward to 12/25,2022
私のAdvent Calendar 2022 一覧


はじめに

Elixirを楽しんでいますか

&>=/2, &<=/2, &</2などは、Function capturingです。
という話を書きます。

&>=/2, &<=/2, &</2

&>=/2, &<=/2, &</2はそれぞれ、enumerableなものから最大値、最小値を取得する関数の第3引数sorterのデフォルト値に指定されています。

第3引数sorterのデフォルト 関数
&>=/2 Enum.max/3
&>=/2 Enum.max_by/4
&<=/2 Enum.min/3
&<=/2 Enum.min_by/4
&</2 Enum.min_max_by/4

たとえば、Enum.max/3をみてみましょう。

一見するとわかりにくいかもしれません。
引数をそれぞれ詳しくみていきます。

  • 第1引数 enumerable
  • 第2引数 sorter: デフォルト値は、&>=/2 ※意味は後述
  • 第3引数 empty_fallback: デフォルト値は、fn -> raise Enum.EmptyError endという引数0個の無名関数

とみます。
な〜んてことない人は、相当なAlchemistです。
つまり、この説明を読んでな〜んてことない人になったあなたはAlchemistです。

What's /2 ?

/2というのは引数が2つという意味です。
/0だと引数が0。
/1だと引数が1。

専門家の間では、arity(アリティ)と呼ばれます。

>=/2

>=/2を深掘りしてみます。
>=/2の内部実装は以下の通りです。

  @doc guard: true
  @spec term >= term :: boolean
  def left >= right do
    :erlang.>=(left, right)
  end

2つの引数を:erlang.>=/2に渡して呼び出しています。

こんな書き方(呼び出し方)はしなくてよいのですが、紹介だけしておくとKernel.>=(4, 3)と書けます。

他も気になる方は、ドキュメント</>を迷わず押してみてください。
ソースコードにジャンプできます。

&>=/2, &<=/2, &</2などは、Function capturing

&>=/2, &<=/2, &</2などは、Function capturingです。

&>=/2を実行した結果と、fn a, b -> a >= b endを実行した結果は同じです。

iex> fc = (&>=/2) 
&:erlang.>=/2

iex> f = fn a, b -> a >= b end
#Function<43.65746770/2 in :erl_eval.expr/5>

iex> fc.(3, 1)
true

iex> f.(3, 1)
true

iex> fc.(3, 4)
false

iex> f.(3, 4)
false

fn a, b -> a >= b endを&記法で書くと、& &1 >= &2となります。
もうここまで来ちゃうと

iex> (&>=/2) == (& &1 >= &2)
true

と、(&>=/2) == (& &1 >= &2)trueとして成立します。

公式ドキュメントは、以下をご参照ください。

その他

何に使うかはこの際、考えません。
以下のようなものを作ることができます。
ソースコード中ではじめてみると、なんだこれ? となること請け合いです。

iex> &+/2
&:erlang.+/2

iex> &-/2
&:erlang.-/2

iex> &++/2
&:erlang.++/2

iex> &<>/2
#Function<43.65746770/2 in :erl_eval.expr/5>

iex> &../2
#Function<43.65746770/2 in :erl_eval.expr/5>

iex> &**/2
&Kernel.**/2

iex> &=/2 
#Function<43.65746770/2 in :erl_eval.expr/5>

iex> &==/2
&:erlang.==/2

iex> & &&/2
#Function<43.65746770/2 in :erl_eval.expr/5>

iex> &!/1
#Function<44.65746770/1 in :erl_eval.expr/5>

iex> &in/2 
#Function<43.65746770/2 in :erl_eval.expr/5>

iex> &**/2 
&Kernel.**/2

Wrapping up

&>=/2, &<=/2, &</2などは、Function capturingです。

Enjoy Elixir
$\huge{Enjoy\ Elixir🚀}$

以上です。

尚々書

先日書いた「Enum.max_by/4 を説明します(Elixir)」の中でもこの記事の内容は一部触れています。
Enum.max_by/4は案外奥が深く、内容が盛り沢山になりました。
&>=/2, &<=/2, &</2は初見殺し感が満載なので、これらに絞って記事を書き起こしました。


I organize autoracex.
And I take part in NervesJP, fukuoka.ex, EDI, tokyo.ex, Pelemay.
I hope someday you'll join us.

We Are The Alchemists, my friends!

  1. @kaizen_nagoya さんの「「@e99h2121 アドベントカレンダーではありますまいか Advent Calendar 2020」の改訂版ではありますまいか Advent Calendar 2022 1日目 Most Breakthrough Generator」から着想を得て、模倣いたしました。