假设我有一些功能:
function g(a,b,c){ return a + b + c }
我想将它变成“咖喱”形式(引文中,因为它本身并不完全是咖喱):
function h(a,b,c){
switch(true){
case (a !== undefined && b !== undefined && c !== undefined):
return a + b + c
case (a !== undefined && b !== undefined && c === undefined):
return function(c){ return a + b + c }
case (a !== undefined && b == undefined && c === undefined ):
return function(b,c){
return (c === undefined) ? function(c){ return a + b + c } : a + b + c
}
default:
return h
}
}
上面的表单具有我想要的部分绑定行为:
h(1) -> h(b,c)
h(1,2) -> h(c)
h(1,2,3) -> 6
h() -> h(a,b,c)
现在我想将这个过程自动化为一些泛型函数curry
,这样在给定任何未加干扰的函数(可能是其参数数量)的情况下,就会生成上述函数。但我不太确定如何实现它。
或者,如果可以自动创建以下表单,那么它也很有趣:
function f(a,b,c){
return function(a){ return function(b){ return function(c){ return a + b + c }}}
}
虽然绑定f
看起来像这样:
f(1)(2)(3) = 6
所以这是非常笨拙和非惯用的,但创建上述形式对我来说似乎更可行。
现在可以通过某个函数生成上述任何一种形式,如果是,怎么做?
答案 0 :(得分:5)
我相信你可以简单地使用Function.prototype.bind
。这为您提供了所需的所有灵活性,您可以立即获得函数的结果,或者只是将另一个值推入参数,直到您决定执行。
function sum() {
return [].reduce.call(arguments, function (c, n) {
return c + n;
});
}
sum(1, 2); //3
var sum2 = sum.bind(null, 1, 2);
sum2(); //3
var sum3 = sum2.bind(null, 3);
sum3(); //6
您还可以使用辅助函数,如:
function curry(fn) {
var c = curry.bind(this, fn = fn.bind.apply(fn, [this].concat([].slice.call(arguments, 1))));
c.exec = fn;
return c;
}
curry(sum, 1, 2)(3)(4, 5)(6, 7, 8).exec(); //36
此外,这非常灵活,因为您不需要连锁,您可以重复使用相同的咖喱功能。
var sumOnePlus = curry(sum, 1);
sumOnePlus.exec(2); //3;
sumOnePlus.exec(3); //4;
答案 1 :(得分:3)
这是我的尝试:
function curry(fn, len) {
if (typeof len != "number")
len = fn.length; // getting arity from function
return function curried() {
var rlen = len - arguments.length;
if (rlen <= 0) // then execute now
return fn.apply(this, arguments);
// else create curried, partially bound function:
var bargs = [this]; // arguments for `bind`
bargs.push.apply(bargs, arguments);
return curry(fn.bind.apply(fn, bargs), rlen);
};
}
这不是partial application(在bind
method的JS中很容易),但是真正的功能currying。它适用于任意但固定的arity的任何功能。对于可变参数函数,您可能需要不同的执行触发器,可能在不再传递任何参数时,或者在@plalx'的答案中使用exec
方法。
答案 2 :(得分:0)
这样的事情怎么样:
function makeLazy(fn) {
var len = fn.length;
var args = [];
return function lazy() {
args.push.apply(args, arguments);
if (args.length < len) {
return lazy;
} else {
return fn.apply(this, args);
}
}
}
function f(a,b,c) { return a + b + c; }
var lazyF = makeLazy(f);
lazyF(1)(2)(3); // 6
var lazyF = makeLazy(f);
lazyF(1,2)(3); // 6
如果您想要一个可重复使用的功能(我想我无法准确说出您想要的内容),那么这将有效:
function makeCurry(fn) {
return function curry() {
var args = [].slice.call(arguments);
return function() {
return fn.apply(this, args.concat.apply(args, arguments));
};
}
}
function f(a,b,c) { return a + b + c; }
var curryF = makeCurry(f);
var addOneTwoAnd = curryF(1,2);
addOneTwoAnd(3); // 6
addOneTwoAnd(6); // 9
答案 3 :(得分:0)
函数的bind()
方法让你绑定函数内的this
以及绑定额外的参数。因此,如果您为null
参数传递this
,则可以使用bind()
将参数调整到函数中。
function g(a,b,c){ return a + b + c }
var g_1 = g.bind(null, 1);
console.log(g_1(2, 3)); // Prints 6
var g_1_2 = g.bind(null, 1, 2);
console.log(g_1_2(3)); // Prints 6
检查Javascript Function bind()以获取使用bind()
绑定参数的详细信息和交互式示例。
答案 4 :(得分:0)
请检查curry库。
无论有多少参数,它都可以将任何函数转换为咖喱。
示例:
> var curry = require('curry');
undefined
> var add = curry(function(a, b, c, d, e) { return a + b + c + d + e; });
undefined
> add(1)
[Function]
> add(1,2,3,4,5)
15
> add(1,2)(3,4)(5)
15
>