定义
curry**
translating
the evaluation of a function that takes multiple args(多参函数)
into
evaluation a sequence of functions,each with a single arg(一系列单参函数).
即:f(x, y, z) => f(x)(y)(z)
被 curry 化的函数,一般地,参数凑齐了,就会执行,如 loadsh 就是这样处理的。但并没有规范的做法,所以也可以是 f(x, y, z) => f(x, y)(z) 或者 f(x)(y)(z)() 或者 f(x)(y)(z).run() 等等。
It provides a way of automatically managing how arguments are passed to functions and expression.
一些语言中,几乎总是使用 curry 实现多参函数,如 ML/Haskell。在这些语言中,函数只能有一个参数(规范做法)。
currying 与 partial application 有点类似,但不一样。
只接收一个参数的成为一元函数,接收两个参数称为两元参数,接收多个参数的称为多元函数。接收不确定参数的称为变参函数。柯里化是把一个多参数函数转换成一个嵌套的一元函数的过程。
通用 curry 函数
参数够了就执行:
const curry = (fn) => {
return function curryFunc(...arg) {
if (arg.length < fn.length) {
return function () {
return curryFunc.apply(null, [...arg, ...arguments]);
};
}
return fn.apply(null, arg);
}
};
const func = (a, b) => console.log(a - b);
curry(func)(1)(2)
专用 curry 函数
对使用场景有要求,不具备通用性:
function add(x, y){ return x + y }
function sub(x, y){ return x - y; }
function mul(x, y){ return x * y;}
function curry(f, x){
return function(y){
return f(x, y);
}
}
curry(add, 3)(4); // 7
curry(sub, 8)(6); // 2
curry(mul, 5)(6); // 30
参数为0个时触发调用
const coreAdd = (...rest) => {
const args = rest
return args.reduce((acc, element) => ( acc += element ), 0)
}
function addCurry() {
const args = Array.prototype.slice.call(arguments)
return function() {
const newArgs = Array.prototype.slice.call(arguments)
const totalArgs = newArgs.concat(args)
if(newArgs.length === 0) return coreAdd(...totalArgs)
return addCurry(...totalArgs)
}
}
const addValue = addCurry(2, 3)(1)(8, 5)()
alert(addValue) // 19
https://medium.com/@anilchaudhary453/method-chaining-currying-javascript-b6fc3324592c
触发条件是显式 .result()
function add (num) {
function adder (n) {
if(n !== undefined) {
num += n
return adder
} else {
return num
}
}
adder.result = function() {
return num
}
return adder
}
add(1)(2)(3)(4)(5).result() // 15
add(1)(2)(3).result() // 6
add(1).result() // 1
lodash 中的 curry
lodash 中的 curry 支持 placeholder,以便于调整参数的提供次序。
var abc = function(a, b, c) {
return [a, b, c];
};
var curried = _.curry(abc);
curried(1)(2)(3);
// => [1, 2, 3]
curried(1, 2)(3);
// => [1, 2, 3]
curried(1, 2, 3);
// => [1, 2, 3]
// Curried with placeholders.
curried(1)(_, 3)(2);
// => [1, 2, 3]
参考:https://lodash.com/docs/#curry
偏应用
允许开发者部分地应用函数,即将给定函数的部分参数固化,然后返回一个函数,该函数仅接收未固化的参数。
通用 partial 函数
Function.prototype.partial = function(...args){
for (let i = args.length; i < this.length; i++){
args.push(undefined) // 补齐,跟fn的参数列表对应上
}
return (...remainArgs) => {
let realArgs = []
let j = 0;
args.forEach((arg, i) => {
if(arg === undefined){
realArgs.push(remainArgs[j++])
} else {
realArgs.push(arg)
}
})
return this(...realArgs)
}
}
使用示例 1
let timer3s = setTimeout.partial(undefined, 3000)
timer3s(() => console.log('hello')) // 3s后输出hello
timer3s(() => console.log('hello2')) // 3s后输出hello2
timer3s(() => console.log('hello3')) // 3s后输出hello3
使用示例 2
function add4(a,b,c,d) { return a + b + c + d }
var _add4 = add4.partial(1,undefined,3,undefined);
_add4(2,4) // 10
_add4(3,5) // 12
参考:
https://simple.wikipedia.org/wiki/Currying
https://en.wikipedia.org/wiki/Currying
https://javascript.info/currying-partials
https://blog.benestudio.co/currying-in-javascript-es6-540d2ad09400
https://blog.bitsrc.io/understanding-currying-in-javascript-ceb2188c339
https://codeburst.io/currying-in-javascript-ba51eb9778dc
https://github.com/lodash/lodash/blob/npm/_createCurry.js