JavaScript 中的函数柯里化(Currying)

JavaScript 中的函数柯里化(Crurring)

将一个多元的函数转换为嵌套一元函数的过程,我们称之为柯里化。函数柯里化通常与
闭包 以及 分步应用程序(partial application) 混合在一起。把它们从场景中拆
分出来,我觉得会更容易理解一些。

按照参数的个数定义元的概念。如:

1
2
3
4
5
6
7
8
9
10
// 一元
const identity = (x) => x

// 两元

const add = (x, y) => x +y

// 多元

const variadic = (x, ...rest) => ...

由上面的定义我们知道,柯里化是指将多元参数转换为转换为一元函数的过程。为什么一
元函数这么重要呢?函数式语言 ML 以及 Haskell 所有函数必须只有一个参数,实现
多参的效果只能用 curry 技术。

柯里化

函数柯里化实际上是:

1
f: X × Y → R

转换为:

f’: x -> (y -> R)

很容易将上面的表达式翻译为柯里化的 add 函数:

1
const add = x => y => x + y

函数的调用方式由原来的 add(1,2) 变成了 add(1)(2)。注意每一次的参数拆解,都返回
了一个新的函数,可以连续的括号调用。

闭包与部分应用程序

对于已经 curry 的 add 函数,如果我们需要一个 +1 的功能,可以这样来做:

1
2
3
4
5
6
7
8
9
10
// curried add
const add = x => y => x + y

const increment = add(1)

// 此时我们定义了一个 increment 函数,传了一个参数 1,相当于
// 得到一个新函数 (y) => 1 + y, 继续使用这个新函数

increment(2) // 3
increment(3) // 4

在定义 increment 函数时,我们定义了一个闭包。传入的参数 1 ,将会被以后调用的过
程利用。而 increment = add(1) 又是一个部分应用程序的例子。

所以 部分应用程序 和 curry 的区别是什么?部分应用程序利用了 curry 的技术,但是
又不去直接用括号调用到底,而是取一个中间变量。这样的好处是什么呢?

如果说,有一步需要一个很大的计算量,调用到底,每次都得计算。而部分用用程序却可
以,计算一次,以后通过闭包去拿这个值,性能会高一些。