元に戻せるほうのカリー化入門

# 想定読者

高階関数、カリー化、部分適用、クロージャ
などの言葉を目にするたび不安になってしまい
それぞれの意味を何度も調べてしまう人へ[^誰]。

カリー化の反対にあたる逆カリー化に焦点を当て、
もう忘れないように理解をまとめておきたい。

[^誰]: おもに自分のためであり、言うまでもないが、記述の正しさは保障できない。



# 高階関数

引数もしくは戻値が関数であるとき
その関数を[高階関数](https://ja.wikipedia.org/wiki/高階関数)と呼ぶらしい。

```javascript:高階関数
const apply = f => x => f(x)
```

関数 `apply` は１引数関数 `f` を引数に取って
関数 `x => f(x)` を返すので高階関数と言える。

関数の関数という構造は何となく神秘的で
特別な名前を付けたくなる気持ちは分かる。

しかし、本質的に重要なのは
数値などと同じように関数を扱えること[^first-class object]
なのではないかと個人的には思う。

[^first-class object]: 関数が[第一級オブジェクト](https://ja.wikipedia.org/wiki/第一級オブジェクト)であること。[関数の集まり](https://ja.wikipedia.org/wiki/指数対象)が型であること。

---

引数もしくは戻値が数値であるとき
その関数を数値関数と呼んでみよう。

```javascript:数値関数
const succ = n => n + 1
```

関数 `succ` は数値 `n` を引数に取って
数値 `n + 1` を返すので数値関数と言える。

それはそうであると感じるのではないだろうか。
高階関数もその程度の理解で良いと思われる。



# カリー化と逆カリー化

カリー化と逆カリー化は
変換と逆変換の関係に相当する。

変換してから逆変換すると元に戻る[^逆]。
カリー化とは元に戻せる変換である。

[^逆]: 逆変換してから変換すると元に戻る。どちらを逆と呼ぶかは趣味の問題だろう。

## 変換

カリー化とは次のような変換のことだ。

```javascript:カリー化
const curry = f => x => y => f(x, y)
```

[__高階関数__](#高階関数) `curry` は２引数関数 `f` を
[__高階関数__](#高階関数) `x => y => f(x, y)` に変換する。

例として、次の２引数関数 `add` を考える。

```javascript:足し算
const add = (x, y) => x + y
```

当然ではあるが `add(2,3)` $=$ `5` となる。
カリー化された[__高階関数__](#高階関数) `curry(add)` は
同様に `curry(add)(2)(3)` $=$ `5` である。

## 逆変換

逆カリー化とは次のような逆変換のことだ。

```javascript:逆カリー化
const uncurry = g => (x, y) => g(x)(y)
```

[__高階関数__](#高階関数) `uncurry` は[__高階関数__](#高階関数) `g` を
２引数関数 `(x, y) => g(x)(y)` に逆変換する。

例として、次の[__高階関数__](#高階関数) `add` を考える。

```javascript:足し算
const add = x => y => x + y
```

当然ではあるが `add(2)(3)` $=$ `5` となる。
逆カリー化された２引数関数 `uncurry(add)` は
同様に `uncurry(add)(2, 3)` $=$ `5` である。

## 変換と逆変換

再び例として、次の２引数関数 `add` を考える。

```javascript:足し算
const add = (x, y) => x + y
```

[__変換__](#変換) `curry` と[__逆変換__](#逆変換) `uncurry` に対して
`add(2, 3)` $=$ `uncurry(curry(add))(2, 3)` $=$ `5`
が成り立つことを確認できるだろう。

これは任意の引数 `(x, y)` に対して成り立ち、
`add` $=$ `uncurry(curry(add))` である[^関数の等価性]。

[^関数の等価性]: 任意の引数に対して戻値が等しいとき２つの関数は等しい。

---

任意の２引数関数 `f` に対して、
カリー化された関数 `curry(f)` は
逆変換 `uncurry` で元の関数 `f` に戻せる。

![カリー化](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268212/39a8de87-480a-ab43-7cd1-3ffe013b65c2.png)

```javascript:２引数関数
const add      = (x, y) => x + y
const mul      = (x, y) => x * y
const constant = (x, _) => x
```

変換により `f` と `curry(f)` は[１対１対応](https://ja.wikipedia.org/wiki/全単射)する。



# 部分適用

部分適用とは次のような変換のことだ。

```javascript:部分適用
const papply = (f, x) => y => f(x, y)
```

[__高階関数__](#高階関数) `papply` は２引数関数 `f` と引数 `x` の
組 `(f, x)` を１引数関数 `y => f(x, y)` に変換する。

例として、次の２引数関数 `mul` と `constant` を考えよう。

```javascript:掛け算と定数
const mul      = (x, y) => x * y
const constant = (x, _) => x
```

第１引数に `0` を部分適用すれば以下となる。

```javascript:部分適用
const mul0      = papply(mul, 0)
const constant0 = papply(constant, 0)
```

この関数 `mul0` は全てを `0` にする。
`[1, 2, 3].map(mul0)` $=$ `[0, 0, 0]`

また関数 `constant0 ` も全てを `0` にする。
`[1, 2, 3].map(constant0)` $=$ `[0, 0, 0]`

---

上記の関数 `mul0` と `constant0` は
[__変換__](#変換) `curry` を用いて次のようにも書ける。

```javascript:部分適用
const mul0      = curry(mul)(0)
const constant0 = curry(constant)(0)
```

変換 `papply` と `curry` は、確かに似て見えて、
同じことをしていてるように感じるかもしれない。

ここで注目すべきは `mul0` や `constant0` を
元の `(mul, 0)` や `(constant, 0)` に戻せるかどうかだ。

---

関数 `mul0` と `constant0` は全てを `0` にする。
つまり `mul0` $=$ `constant0` であることに注意しよう。

例えば部分適用された関数 `mul0` の逆変換を試みても、
`(mul, 0)` と `(constant, 0)` のどちらに移せば良いか
分からないため、元の `(mul, 0)` に戻せない。

![部分適用](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268212/43507705-f799-4cdd-73ed-ded3aeeb505f.png)

```javascript:２引数関数
const add      = (x, y) => x + y
const mul      = (x, y) => x * y
const constant = (x, _) => x
```

[__変換と逆変換__](#変換と逆変換)で見たような[１対１対応](https://ja.wikipedia.org/wiki/全単射)こそが
元に戻せるという性質をあらわしている。



# クロージャ

環境とラムダ式(アロー関数)の両者を
合わせたものをクロージャと呼ぶらしい[^クロージャ]。

```javascript:クロージャ
{
  let a = 2
  let b = 1
  const closure = x => a*x + b
}
```

関数 `closure` の中では宣言されておらず
外の環境で宣言されているような変数 `a` と `b` を
関数の宣言時に閉じ込めるイメージだろうか。

変数 `a` と `b` をグローバル変数だと思えば、
次のような関数もクロージャと考えられるだろう。

```javascript:クロージャ
const closure = x => a*x + b
```

変数の数はいくつでも良いと思うので、
たまたま０個な次のような関数もクロージャだろう。

```javascript:クロージャ
const closure = x => 2*x + 1
```

クロージャと関数を同一視してしまっても
実用上はなんの問題もないような気がする。

---

と思っていたけれど、例えば Rust においては
関数ポインタ型 `fn()` とクロージャ型 `Fn()` の
区別を意識する必要がありそうだ[^Rust]。

コンパイラの気持ちになってみれば、
実行前に内容がある程度分かる関数ポインタ型と
環境に応じて内容が変わるクロージャ型を
同一視されると困るというのは分かる気もする。

[^Rust]: [簡潔なQ「Rustの関数ポインタの落とし穴」(2018-02-11)](https://qnighy.hatenablog.com/entry/2018/02/11/220000)

---

狭義には次のような[__高階関数__](#高階関数) `enClosure` の戻値
すなわち関数 `closure ` をクロージャと呼ぶだろう。

```javascript:エンクロージャとクロージャ
const enClosure = (a, b) => {
  const closure = x => a*x + b
  return closure
}
```

これを次のように書けば、単なる[__高階関数__](#高階関数)に見える。

```javascript:エンクロージャとクロージャ
const enClosure = (a, b) => x => a*x + b
```

やはりクロージャと関数を同一視しても良さそうだ。

---

クロージャの例としてよく見るカウンターを考えよう。

```javascript:カウンター
const newCounter = count => {
  const counter = del => {
    count = count + del
    return count
  }
  return counter
}
```

これまでと異なり変数 `count` は可変だが、
[__高階関数__](#高階関数) `newCounter` の戻値 `counter` を
クロージャと呼んでいるに過ぎないだろう。

少し苦しいが次のように書けば、単なる[__高階関数__](#高階関数)だ。

```javascript:カウンター
const newCounter = count => del => count = count + del
```

クロージャとは関数だと理解しておくことにする。
そのほうが覚えるべきことが減って簡単なはずだ。



# まとめ

カリー化と部分適用の違いについては
分かりやすい解説がたくさんあるけれど、
特に[１対１対応](https://ja.wikipedia.org/wiki/全単射)を重視したような解説は
見つけることができなかったので書いてみた。

タイトルに関しては次記事のリスペクトです。
[__「食べられないほうのカリー化入門」(2013-07-22)__](https://qiita.com/KDKTN/items/6a27c0e8efa66b1f7799)

食べ物のカレーを元の材料には戻せないので、
元に戻せるかどうかでもカレー化とカリー化の
両者を区別することが可能だと思いました。



[^クロージャ]: [檜山正幸のキマイラ飼育記 (はてなBlog)「結局、クロージャって」(2007-05-29)](https://m-hiyama.hatenablog.com/entry/20070529/1180401176)