请在将其标记为重复之前阅读。
我不是要求单一的咖喱电话。
此函数乘以乘法(4,4,4)// 64
function multiplication(...args) {
return args.reduce((accum, val) => accum * val, 1)
}
但是我正在努力实现其他目标......
同样的功能也应该乘以咖喱函数括号。 e.g。
/*
which return the multiplication of three numbers.
The function can be called in any of the following forms:
multiply(2, 3)(4) => 24
multiply(2)(3, 4) => 24
multiply(2)(3)(4) => 24
multiply(2, 3, 4) => 24
*/
请帮助。
在摆弄了大量代码并阅读一些堆栈答案之后。
最后我想出来了。但它仍然不能满足这个multiply(2)(3, 4) => 24
但其他情况下工作正常
multiply(2,3,4)
multiply(2,3)(4)
multiply(2)(3)(4)
var multiply = function(...args) {
if (args.length === 3) {
return args[0] * args[1] * args[2];
} else {
return function() {
args.push([].slice.call(arguments).pop());
return multiply.apply(this, args);
};
}
}
multiply(2)(3, 4) => 24 fail
答案 0 :(得分:9)
这是一个通用的解决方案,通过重复调用bind
直到有足够的参数传递为止。
function curry(func, arity = func.length) {
return function (...args) {
if (args.length >= arity) {
return func(...args);
} else {
return curry(func.bind(this, ...args), arity - args.length);
}
};
}
const multiply = curry((a, b, c) => a * b * c);
console.log(multiply(2, 3)(4));
console.log(multiply(2)(3, 4));
console.log(multiply(2)(3)(4));
console.log(multiply(2, 3, 4));
答案 1 :(得分:3)
您的代码
var multiply = function(...args) {
if (args.length === 3) {
return args[0] * args[1] * args[2];
} else {
return function() { // ***
args.push([].slice.call(arguments).pop()); // ***
return multiply.apply(this, args);
};
}
}
***这两行需要改变,你几乎就在那里,实际上非常接近
var multiply = function(...args) {
if (args.length === 3) {
return args[0] * args[1] * args[2];
} else {
return function(...args2) { // ***
args.push(...args2); // ***
return multiply.apply(this, args);
};
}
}
console.log(multiply(2, 3)(4))
console.log(multiply(2)(3, 4))
console.log(multiply(2)(3)(4))
console.log(multiply(2, 3, 4))

ES6让它更干净
const multiply = (...args) => (args.length === 3) ? args[0] * args[1] * args[2] : (...args2) => multiply(...args.concat(args2));
console.log(multiply(2, 3)(4))
console.log(multiply(2)(3, 4))
console.log(multiply(2)(3)(4))
console.log(multiply(2, 3, 4))

答案 2 :(得分:2)
这是一个类似于4castle的答案,它使用额外的rest参数而不是Function.prototype.bind
const curry = (f, ...xs) => (...ys) =>
f.length > xs.length + ys.length
? curry (f, ...xs, ...ys)
: f (...xs, ...ys)
const multiply =
curry ((a, b, c) => a * b * c)
console.log (multiply (2, 3) (4)) // 24
console.log (multiply (2) (3, 4)) // 24
console.log (multiply (2) (3) (4)) // 24
console.log (multiply (2, 3, 4)) // 24
console.log (multiply () () () (2, 3, 4)) // 24
但是当可变函数发挥作用时,依赖于length
属性是一个函数 - 这里,partial
更容易理解,当函数的参数不会被提供时显式地传递整体,它适用于可变函数。
const multiply = (x, ...xs) =>
x === undefined
? 1
: x * multiply (...xs)
const partial = (f, ...xs) =>
(...ys) => f (...xs, ...ys)
console.log (partial (multiply) (2, 3, 4)) // 24
console.log (partial (multiply, 2) (3, 4)) // 24
console.log (partial (multiply, 2, 3) (4)) // 24
console.log (partial (multiply, 2, 3, 4) ()) // 24
console.log (multiply (2, 3, 4, 5, 6, 7)) // 5040
console.log (partial (multiply, 2, 3, 4) (5, 6, 7)) // 5040
console.log (partial (partial (multiply, 2, 3), 4, 5) (6, 7)) // 5040
部分申请与currying相关,但不完全相同。我在this answer和this one
中写下了一些差异答案 3 :(得分:0)
这是一个最小的咖喱功能
const curry = (fn, ...args) =>
args.length >= fn.length ? fn(...args) : curry.bind(null, fn, ...args)
高级别说明:
我们想构建一个函数,在精神上与Thrush(f => a => f(a)
)类似,但具有可变输入。我们希望将输入部分地应用于此函数,为第一个参数和其他所需参数传递curried函数f
,直到满足或超过f.length
给出的函数的适当arity为止
详细说明:
假设我们有一些添加功能,
const add = (a,b,c) => a+b+c
我们讨好它
const curriedAdd = curry( add )
以下是发生的事情:
curry( add, 10 )
)args.length >= fn.length
为false
,因为我们未提供args
且该函数的长度为3 很酷,所以我们基本上只是现在只回到curry
接下来我们称之为
const inc = curriedAdd(0,1)
现在发生以下情况
我们调用curried函数。 curriedAdd
add
与this
绑定为第一个参数(null
设置为add
后)。看起来像这样
const inc = curry.bind(null,add)(0,1)
这里当我们调用咖喱时,args
又是函数的第一个参数。 [0,1]
现在是两个args.length >= fn.length
的列表。
add.length
为false,因为args.length
为3,curry
为2。 add
的新副本,并将其绑定到[0,1]
,并将两个参数inc
传播到bind。 curry.bind(null, add, 0, 1)
不是const six = inc(5)
很酷,现在我们称之为
inc
但curry.bind(null,add,0,1)
只是curry
因此我们像以前一样打电话给args.length >= fn.length
。这一次true
为add
,并使用所有三个参数调用args.length >= fn.length
这个currying函数的一个重要部分是谓词为args.length === fn.length
而不是const six = inc(5,undefined)
,否则会失败
const concatWith = curry( (fn,a,b) => a.concat(fn(b)) )
const collectObjectValues = concatWith(Object.values)
[ {a: 1, b: 2}, {c: 3} ].reduce( collectObjectValues, [] )
// [1,2,3]
这似乎并不重要,但是,在Javascript中,您可能经常这样做
reduce
.elementor-button:focus,
.elementor-button:hover,
.elementor-button:visited {
color: #fff;
opacity: .9;
}
函数传递一些参数...一个大于我们预期的两个参数(见脚注)。如果我们的curry谓词没有考虑大于场景,那么这段代码就会破坏。
希望这是有益的和有教育意义的。享受!
脚注:
[1] - 确切地说是四,请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
答案 4 :(得分:0)
一个非常基本的curry
函数可以通过使用递归在JavaScript中实现,如下所示;
var curry = f => f.length ? (...a) => curry(f.bind(f,...a)) : f();
function multiplyDivide (n,m,o,p){
return n * m / o * p;
}
var curry = f => f.length ? (...a) => curry(f.bind(f,...a)) : f(),
cmd = curry(multiplyDivide);
console.log(cmd(4,5,2,10)); // <- 100
console.log(cmd(4)(5,2,10)); // <- 100
console.log(cmd(4,5)(2,10)); // <- 100
console.log(cmd(4,5,2)(10)); // <- 100
console.log(cmd(4)(5)(2,10)); // <- 100
console.log(cmd(4)(5)(2)(10)); // <- 100
&#13;
但是,当我们检查在函数定义中定义和设置的curry
属性时,上述f.length
函数对于接受确定数量参数的函数有效。这是一种正常的函数行为,因为纯函数具有固定类型,它与所需的内容和它所提供的内容绑定在一起。但是,JS是松散类型的,而不是纯函数式语言。它可以无限期地获取许多论据。
对于rest
运算符指定的无限多个参数,例如(...a)
,function.length
属性为0
,强制我们使用arguments.length
来决定停止。在这种情况下,curried函数将每次为您提供一个新函数,以便您能够输入新参数,直到您最终调用它而没有参数来获得结果。
function prodall(...a){
return a.reduce((p,c) => p*c);
}
var curry = f => (...a) => a.length ? curry(f.bind(f,...a)) : f(),
cpa = curry(prodall);
console.log(cpa(4,5,2,10)()); // <- 400
console.log(cpa(4)(5,2,10)()); // <- 400
console.log(cpa(4,5)(2,10)()); // <- 400
console.log(cpa(4,5,2)(10)()); // <- 400
console.log(cpa(4)(5)(2,10)()); // <- 400
console.log(cpa(4)(5)(2)(10)()); // <- 400
console.log(cpa(4)(5)(2)(10,3)()); // <- 1200
&#13;