なぜ Elixir の匿名関数の呼び出しにはドットが必要なのか？

# なぜ Elixir の匿名関数の呼び出しにはドット`.`が必要なのか？

#### 匿名関数が束縛された変数と関数の名前が同じときの文法上の区別のため

Elixirでは、変数とモジュール関数に同じ名前を付けることができる。また、関数は、関数名とアリティによって区別されるが、匿名関数が束縛された変数はアリティによって区別することはできない。[^1]

もし、匿名関数が束縛された変数と、モジュール関数が同じ名前を持っていたとしても、Elixirはオーバーロードは行わない。そもそも行うべきではない。もし、Elixirがオーバーロードを行うという言語設計だったとすると、アリティによって区別される関数をアリティなしの匿名関数でオーバーロードすることになってしまう。アリティによって異なる関数として区別されていたものが、匿名関数でオーバーロードすることで区別を失う[^4]のは、混乱のもとだ。このようなオーバーロードには価値がないであろうから、匿名関数の変数でモジュール関数をオーバーロードできないことは言語設計上妥当といえる。

そこで変数に束縛された匿名関数の呼び出しと、モジュール関数の呼び出しを文法上識別できる方法が必要になる。Elixirの場合には変数の後にドット`.`をつけることとなった。

#### 文法上区別する別の例

`Kernel.then/2`という関数は、第一引数に値を、第二引数にアリティが1の匿名関数を取り、匿名関数に値を与えて計算した結果を返す。

```elixir
# 匿名関数の場合
"Hello world"
|> then(&IO.puts/1)

# モジュール関数の場合
"Hello world"
|> IO.puts
```

Hex[^2]では特に匿名関数に限定しているとは読めないが`then`は匿名関数のみを引数にとることができるようだ。モジュール関数であれば、thenがなくても動作する。[^3]

#### 他の記号ではなく`.()`を使う理由

文法上区別が必要なことはわかった。ただ別の記号でもよいのに、なぜドットなのか。ここからは独自解釈。モジュール関数を使う場合には、`Module.func()`のようにドットの左側にはモジュール名、ドットの右側には関数が並ぶ。 もし、動的ディスパッチのように、モジュールの部分を変数にすると、`variable.func()`となる。無名関数の場合には、名前なしの `""`　という関数がひとつだけ定義されたモジュールだと思うと、`variable.()`という記法になったと解釈ができなくもない。

理由というよりドット記法のメリットを示す方がいいかもしれない。匿名関数を使うとカリー化ができる。複数の引数を持つ関数を一つの引数を持つ関数に変換することだ。カリー化した関数を呼び出すと、以下のようにチェーンを作ることができる。チェーンは連続させることができ、さらにこれを改行することもできる。`.()`ではなく、`()`だとこうはいかない。先行する言語の流儀に即しているわけではないが、馴染みやすい形式に見える。

```elixir
add = fn a -> fn b -> a + b end end

add
.(1) # 最初の引数
.(2) # 二番目の引数
     #3
```

#### 参考までにTypeScriptの場合

TypeScriptの場合には、名前空間を共有しているので関数と変数が同じ名前を持つことはできない。変数に`()`をつけることで、関数の呼び出しができる。TypeScriptの例を見ると、関数と変数の名前空間の共有が匿名関数の()記法による呼び出しの前提条件になることが確かめられる。

##### TypeScriptでは関数と変数が同じ名前を持つことはできない

関数 `sum` とは別に、変数（定数） `sum` を定義しようとすると、エラーになる。

```typescript
function sum(a: number, b: number) {
	return a + b;
}
// const sum = 1;
// Error: Identifier 'sum' has already been declared
```

##### TypeScriptでは変数に`()`をつけて関数呼び出しができる

変数 `add` に束縛された関数呼び出しをするときには、`add()` の文法で呼び出すことができる。

```typescript
const add = function sum(a: number, b: number) {
	return a + b;
}
expect(add(1,2)).toBe(3);
```

#### 参考までにGleamの場合

Gleamは、関数と変数の名前空間を共有している。GleamはElixirと同じBEAMプラットフォームで動く言語。この言語では関数と変数が同じ名前を持つことができるが、関数をアリティによって区別することはできない。匿名変数に`()`をつけて関数呼び出しができる。この例からは、ドット記法は言語設計上の判断（プラットフォームの制約ではない）であることが明らかになる。

##### Gleamでは変数と関数が同じ名前空間を共有する

関数 `sum` と、`main`関数内で定義されるローカル変数 `sum` があった場合、ローカル変数 `sum` に束縛された関数が呼び出される。

```gleam
import gleam/io
import gleam/int

pub fn sum(a: Int, b: Int) {
  a + b
}

pub fn main(){
  let sum = fn(x,y){x - y}
  io.println(int.to_string( sum(1,2)) ) // -1
}
```

##### Gleamでは関数は複数のアリティを持つことができない
引数の数が異なる(アリティが異なる)関数 `sum/3` を定義しようとすると、エラーになる。

```gleam
import gleam/io
import gleam/int

pub fn sum(a: Int, b: Int) {
  a + b
}

// pub fn sum(a: Int, b: Int, c: Int) {
//   a + b + c
// }
// error: Duplicate definition
```

##### Gleamでは変数に`()`をつけて関数呼び出しができる

変数 `func` に関数 `sum` を束縛し、`func`より関数呼び出しをする場合、`func()` の記法で呼び出すことができる。

```gleam
import gleam/io
import gleam/int

pub fn sum(a: Int, b: Int) {
  a + b
}

pub fn main(){
  let func = sum
  io.println(int.to_string( func(1,2)) ) // 3
}
```

[^1]: https://dashbit.co/blog/why-the-dot ←こちらがフォーマルな見解
[^2]: https://hexdocs.pm/elixir/1.12.3/Kernel.html#then/2 
[^3]: 実装を見るとマクロで`<variable>.()`の記法に変換している
[^4]: 匿名関数にもアリティはあるのだが、ひとつの変数名に束縛できるのは１種類の関数×アリティだけで、複数のアリティを持つことができない。