カリー化と部分適用

カリー化と部分適用という概念について簡潔に説明する。

# カリー化 / currying

## 定義

関数 $f$ に対して、次のような関数 $g$ を $f$ の $X$ についてのカリー化という。

$$
f: (X \times Y) \to Z, \quad f(x, y) := z \\\\
g: X \to (Y \to Z), \quad g(x) := f(x, \cdot)
$$

## 例

### 数式

$$
f: (\mathbb{R} \times \mathbb{R}) \to \mathbb{R}, \quad f(x, y) := x - y \\\\
g: \mathbb{R} \to (\mathbb{R} \to \mathbb{R}), \quad g(x) := f(x, \cdot) \\\\
g(1)(2) = -1
$$

注：高校レベルまでの数学で関数を返す関数を扱うことはないので、 $f(x, \cdot)$ という表記や、 $g(1)(2)$ という表記が奇妙に映るかもしれないが、よく使われるものである。

### Scheme

```scheme
(define func (lambda (x y) (- x y)))
(define func_curried (lambda (x) (lambda (y) (func x y))))
((func_curried 1) 2) ; -1
```

### Julia

```jl
func(x, y) = x - y
func_curried(x) = y -> func(x, y)
func_curried(1)(2) # -1
```

### JavaScript

```js
let func = (x, y) => x - y;
let func_curried = x => (y => func(x, y));
func_curried(1)(2); // -1
```

### C++ (C++14以上)

```cpp
auto func = [](auto x, auto y) {
    return x - y;
};
auto func_curried = [](auto x) {
    return [&](auto y) {
        return func(x, y);
    };
};
func_curried(1)(2); // -1
```

### Go

```go
func f(x int, y int) int {
    return x - y
}
func f_curried(x int) func(int) int {
    return func(y int) int {
        return f(x, y)
    }
}
f_curried(1)(2) // -1
```

# 部分適用 / partial application

## 定義

関数 $f$ に対して、次のような $g_y$ を $f$ の $Y$ についての部分適用という。

$$
f: (X \times Y) \to Z, \quad f(x, y) := z \\\\
g_y: X \to Z, \quad g_y(x) := f(x, y)
$$

## 例

### 数式

$$
f: (\mathbb{R} \times \mathbb{R}) \to \mathbb{R}, \quad f(x, y) := x - y \\\\
y := 2 \\\\
g: \mathbb{R} \to \mathbb{R}, \quad g(x) := f(x, y) \\\\
g(1) = -1
$$

### Scheme

```scheme
(define func (lambda (x y) (- x y)))
(define y 2)
(define func_partial (lambda (x) (func x y)))
(func_partial 1) ; -1
```

### Julia

```jl
func(x, y) = x - y
y = 2
func_partial(x) = func(x, y)
func_partial(1) # -1
```

### JavaScript

```js
let func = (x, y) => x - y;
const y = 2;
let func_partial = x => func(x, y);
func_partial(1); // -1
```

### C++ (C++14以上)

```cpp
auto func = [](auto x, auto y) {
    return x - y;
};
const auto y = 2;
auto func_partial = [](auto x) {
    return func(x, y);
};
func_partial(1); // -1
```

### Go

```go
func f(x int, y int) int {
    return x - y
}
const y = 2
func f_partial(x int) int {
    return f(x, y)
}
f_partial(1) // -1
```

# カリー化と部分適用の関係

部分適用はカリー化で表現できる。

例えば、次のような関数 $f$ を定義したとする。
$$
f: A \times B \times C \to Z, \quad (a, b, c) \mapsto z
$$
これに対して $f$ の $A$ についてのカリー化を $g$ とすると、
$$
g: A \to (B \times C \to Z), \quad a \to g(a)
$$
であり、
$$
g(a): B \times C \to Z, \quad (b, c) \mapsto z
$$
であるから、 $g(a)$ は $f$ の $A$ についての部分適用 $f_A$ に等しい。
$$
f_A: B \times C \to Z, \quad (b, c) \mapsto z \\\\
g(a) = f_A
$$
逆にこのカリー化 $g$ を部分適用 $f_A$ を使って定義することもできて、
$$
g: A \to \{f_A\}, \quad a \mapsto f_A
$$
と定義できる。つまりカリー化は部分適用を求める関数である。その意味でカリー化は部分適用よりも抽象的な概念である。

# カリー化と部分適用という言葉

上の定義ではカリー化 $g$ を関数として扱ったが、カリー化 $g$ を求める手続きをカリー化と呼んだり、カリー化 $g$ を（広義の）部分適用として呼んだりする場合もある。しかし、カリー化と部分適用という言葉が使い分けられている場合、上の定義のような理解をしておくとすっきりする。

# カリー化と部分適用のメリット

## 部分適用のメリット

次のような関数 $f$ を考えよう。
$$
f: X_1 \times \cdots \times X_n \times Y_1 \times \cdots \times Y_m \to Z \\\\
f(x_1, \cdots, x_n, y_1, \cdots, y_m) := z
$$

簡略化のために引数の定義域を$\mathcal{X} := X_1 \times \cdots \times X_n, \mathcal{Y} = Y_1 \times \cdots \times Y_m$、引数を$\mathbf{x} := (x_1, \cdots, x_n), \mathbf{y} = (y_1, \cdots, y_m)$として、$f(\mathbf{x}, \mathbf{y}) := f(x_1, \cdots, x_n, y_1, \cdots, y_m)$とする。

$$
f: \mathcal{X} \times \mathcal{Y} \to Z \\\\
f(\mathbf{x}, \mathbf{y}) := z
$$

今、関数 $f$ の引数 $\mathbf{x}$ は定数であって、変数部分は $\mathbf{y}$ だけとみなせるとしよう。その場合、いちいち
 $f(\mathbf{x}, \mathbf{y})$ と書くことは、意識する必要のない $\mathbf{x}$ を何度も書くことになってしまう。これは冗長であるし、表現を複雑にする。そのようなとき、新しく $\mathbf{x}$ を定数に制限した関数 $f_\mathbf{x}$ を次のように定義して、使用すれば簡潔さを維持できる。

$$
f_\mathbf{x}:  \mathcal{Y} \to Z \\\\
f_\mathbf{x}(\mathbf{y}) := f(\mathbf{x}, \mathbf{y}) = z
$$

これが部分適用のメリットである。

## カリー化のメリット

部分適用は関数$f$の意識する必要のない引数$\mathbf{x}$を切り離すところに価値があった。一方で、$\mathbf{x}$の値について固定してしまうので後で変更できなくなってしまう。そもそも部分適用したくなる場合というのは$\mathbf{x}$と$\mathbf{y}$を切り離した方が見通しが良くなる場合に相当する。このような場合に$f_\mathbf{x}(\mathbf{y})$を$\mathbf{x}$の関数とみるのがカリー化である。
$$
f_{\text{currying}\ \mathcal{X}}: \mathcal{X} \to (\mathcal{Y} \to Z) \\\\
f_{\text{currying}\ \mathcal{X}}(\mathbf{x}) = f_\mathbf{x}
$$

カリー化では、部分適用のように$\mathbf{x}$を隠し、$\mathbf{y}$を変数として見る場合に加えて、$\mathbf{y}$を隠し、$\mathbf{x}$を変数として見ることができるようになっている。これがカリー化のメリットである。