什么是柯里化?

问题来源:Leetcode:2632. 柯里化

image-20230520162008987

问题分析

抄袭于:

作者:coderyoo
链接:https://leetcode.cn/problems/curry/solution/shen-ru-li-jie-ke-li-hua-by-coderyoo-rx4e/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处

柯里化(Currying)是一种函数转换的技术,它是以逻辑学家哈斯凡·柯里(Haskell Curry)的名字命名的。柯里化是指将一个多参数的函数转换为一系列只接受单一参数的函数序列。

在柯里化中,原始函数的参数被逐个应用于一系列嵌套的函数中。每个嵌套的函数都只接受一个参数,并返回一个新的函数,该函数继续接受下一个参数,直到所有参数都被应用完毕。最后,返回的函数执行最初函数的逻辑并返回结果。

省流:柯里化就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数。

问题举例

现在假设有一个这样的函数。

1
2
3
function add(x, y, z) {
return x + y + z
}

柯里化后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 容易理解的版本
function curriedAdd() {
return function(x) {
return function(y) {
return function(z) {
return x + y + z
}
}
}
}

// 简化版本 (利用箭头函数的特性)
const curriedAdd = (x) => (y) => (z) => x + y + z

add手动柯里化后:

1
2
3
4
5
6
7
8
// 1 
const res = curriedAdd(1)(2)(3)

// 2
const add10 = curriedAdd(10)
const add30 = add10(20)
const r1 = add30(50) // 80
const r2 = add30(100) // 130

问题原因

通过对以上案例,可以看出,柯里化函数有两个优势:

  • 复用函数的参数
  • 让函数的职责更加单一

柯里化的应用场景还有很多,比如像日志打印、延迟执行等等。
只要你想封装或抽取参数就可以使用柯里化~

解决方法:

1.自动柯里化

前置知识:如何获取一个函数的参数长度?

  1. 在函数申明体内可以获得运行时的参数长度arguments.length。
  2. 要在函数申明体外获得该函数的参数长度,可以通过Function.prototype.length,也就是fn.length

代码实现

思路

  1. curry的函数需要返回一个函数curried
  2. curried函数可以接收用户的参数,在接收到参数时,需要检查参数的长度是否已经满足原函数的长度。
    1. 满足:那就直接调用原函数
    2. 不满足:就返回一个新的函数,该函数用于接收新的参数,并新的参数与curried的参数进行拼接,继续之后继续调用curried,这样也就形成了递归,可以看下下面的代码。

代码

1
2
3
4
5
6
7
8
9
10
11
12
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) { // 满足原函数的要求
return fn.apply(this, args)
} else {
return function(...newArgs) { // 不满足原函数的要求
return curried.apply(this, args.concat(newArgs))
}
}
};
};


扩展

也可以不通过fn.apply的方式,通过直接调用或fn.call的方式,需要将原参数解构再传递。