如何在未知数量的参数上柯里化一个函数
How to curry a function across an unknown number of parameters
假设我有一个名为 multiplyDivide
的函数
如果我调用 multiplyDivide(2)(3)(4)(6)
它将等同于 2 * 3 / 4 * 6
.
更新:
如果我事先不知道我将采用多少参数,是否可以编写这样的函数?例如,我可以有 multiplyDivide(1)(2)
或 multiplyDivide(1)(2)(3)(4)...(n-1)(n)
你的意思是这样的吗?
var multiplyDivide = function(first){
return function(second){
return function(third){
return function(forth){
return first * second / third * forth;
}
}
}
}
//should be 6
console.log(multiplyDivide(2)(4)(4)(3));
使用函数式方法,您可以创建一个函数,该函数 "curries" 为另一个函数提供参数。您将需要一种方法来告诉函数 return 值,因此在这种情况下,调用函数而不传递任何参数将 return 结果:
function curry(fn, ...values) {
return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}
这个函数最酷的地方在于你可以传递多个参数and/or继续调用函数(1)(2, 3, 4)(5)
。
这里有几个例子:
function curry(fn, ...values) {
return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}
function multiplyDivide(...args) {
return args.reduce((total, next, i) => (i % 2) ? (total / next) : (total * next), args.shift());
}
let x = curry(multiplyDivide)(2)(3, 4)(6)();
console.log(x);
let y = curry(multiplyDivide)(5, 4, 2)(3);
y = y(3, 5)(1)();
console.log(y);
当然,这个例子确实暗示只是简单地重载 multiplyDivide
函数并在您准备好时将您的值传递给它:
function multiplyDivide(...args) {
return args.reduce((total, next, i) => (i % 2) ? (total / next) : (total * next), args.shift());
}
const values = [5, 4, 2, 3, 3];
values.push(5, 1);
console.log(multiplyDivide(...values));
有点可能,但您需要定义终止条件,因为该问题本质上与编写递归函数的问题相同。该函数需要一种方法来判断它应该 return 一个函数还是一个值。
你如何表达对价值观的需求取决于你。一种方法是检查是否传递了参数:
// Using add instead of multiplyDivide to simplify example:
function add (num) {
function adder (n) {
if (n !== undefined) {
num += n;
return adder;
}
else { // terminate
return num;
}
}
return adder;
}
现在你可以做:
var sum = add(1)(2)(3)(4)();
否则它将return一个你可以继续调用的函数:
var x = add(1)(2)(3)(4);
x = x(5)(6)(7);
x = x(8)(9)(10);
var sum = x();
由于在js中函数是对象,所以也可以将值getter实现为静态方法。它不会纯粹是功能性的,但会使 "API" 更明确和更易于阅读:
function add (num) {
function adder (n) {
num += n;
return adder;
}
adder.value = function(){
return num
};
return adder;
}
您可以这样做:
var sum = add(1)(2)(3)(4).value();
您甚至可以通过重写内置的 .valueOf()
和 .toString()
方法来获得乐趣:
function add (num) {
function adder (n) {
num += n;
return adder;
}
adder.valueOf = function(){
return num
};
adder.toString = function(){
return '' + num
};
return adder;
}
您可以这样做:
var sum = add(1)(2)(3)(4) + 5; // results in 15
var txt = add(1)(2)(3)(4) + "hello"; // results in "10hello"
这里的关键是您需要一种方法来告诉函数停止 returning 函数。
这其实是个很好的问题...
柯里化是函数式编程语言最基本的方面之一,您可以在其中传递 return 函数。 JS在某种程度上是一种函数式编程语言,应该可以执行此操作。
所以就像你问题中的那个一样,出于这个或那个原因,人们可能想柯里化一个无限多的参数函数。
OK 让你的功能成为
function multiplyDivide (n,m,o,p){
return n * m / o * p;
}
那么实现实用程序 curry
函数以获得任何给定函数的柯里化版本的方法如下;
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(),
f = curry(multiplyDivide);
res1 = f(4,5,2,10),
res2 = f(4)(5,2,10),
res3 = f(4)(5)(2,10),
res4 = f(4)(5)(2)(10),
res5 = f(4,5)(2,10),
res6 = f(4,5)(2)(10),
res7 = f(4,5,2)(10),
res8 = f(4,5)(2,10);
console.log(res1,res2,res3,res4,res5,res6,res7,res8);
可能有更简单的方法,但这是我能想到的。
function addValues(a, b) {
if(b!=undefined)
return a + b;
return function(b) {
return a + b;
}
}
let output1 = addValues(2)(4); // 6
let output2 = addValues(2,1); // 3
console.log(output1);
console.log(output2)
function multiply(a) {
return function(b) {
return b ? multiply(a*b) : a;
}
}
console.log(multiply(2)());
console.log(multiply(2)(3)());
console.log(multiply(2)(3)(4)());
console.log(multiply(2)(3)(4)(5)());
function add() {
let args = [...arguments];
function addAll(){
let args1 = [...arguments];
return add(...args, ...args1);
}
let total = args.reduce((total, value) => total+value);
addAll.value = total;
return addAll;
}
console.log(add(2)(3)(4).value);
console.log(add(2)(3).value);
假设我有一个名为 multiplyDivide
如果我调用 multiplyDivide(2)(3)(4)(6)
它将等同于 2 * 3 / 4 * 6
.
更新:
如果我事先不知道我将采用多少参数,是否可以编写这样的函数?例如,我可以有 multiplyDivide(1)(2)
或 multiplyDivide(1)(2)(3)(4)...(n-1)(n)
你的意思是这样的吗?
var multiplyDivide = function(first){
return function(second){
return function(third){
return function(forth){
return first * second / third * forth;
}
}
}
}
//should be 6
console.log(multiplyDivide(2)(4)(4)(3));
使用函数式方法,您可以创建一个函数,该函数 "curries" 为另一个函数提供参数。您将需要一种方法来告诉函数 return 值,因此在这种情况下,调用函数而不传递任何参数将 return 结果:
function curry(fn, ...values) {
return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}
这个函数最酷的地方在于你可以传递多个参数and/or继续调用函数(1)(2, 3, 4)(5)
。
这里有几个例子:
function curry(fn, ...values) {
return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}
function multiplyDivide(...args) {
return args.reduce((total, next, i) => (i % 2) ? (total / next) : (total * next), args.shift());
}
let x = curry(multiplyDivide)(2)(3, 4)(6)();
console.log(x);
let y = curry(multiplyDivide)(5, 4, 2)(3);
y = y(3, 5)(1)();
console.log(y);
当然,这个例子确实暗示只是简单地重载 multiplyDivide
函数并在您准备好时将您的值传递给它:
function multiplyDivide(...args) {
return args.reduce((total, next, i) => (i % 2) ? (total / next) : (total * next), args.shift());
}
const values = [5, 4, 2, 3, 3];
values.push(5, 1);
console.log(multiplyDivide(...values));
有点可能,但您需要定义终止条件,因为该问题本质上与编写递归函数的问题相同。该函数需要一种方法来判断它应该 return 一个函数还是一个值。
你如何表达对价值观的需求取决于你。一种方法是检查是否传递了参数:
// Using add instead of multiplyDivide to simplify example:
function add (num) {
function adder (n) {
if (n !== undefined) {
num += n;
return adder;
}
else { // terminate
return num;
}
}
return adder;
}
现在你可以做:
var sum = add(1)(2)(3)(4)();
否则它将return一个你可以继续调用的函数:
var x = add(1)(2)(3)(4);
x = x(5)(6)(7);
x = x(8)(9)(10);
var sum = x();
由于在js中函数是对象,所以也可以将值getter实现为静态方法。它不会纯粹是功能性的,但会使 "API" 更明确和更易于阅读:
function add (num) {
function adder (n) {
num += n;
return adder;
}
adder.value = function(){
return num
};
return adder;
}
您可以这样做:
var sum = add(1)(2)(3)(4).value();
您甚至可以通过重写内置的 .valueOf()
和 .toString()
方法来获得乐趣:
function add (num) {
function adder (n) {
num += n;
return adder;
}
adder.valueOf = function(){
return num
};
adder.toString = function(){
return '' + num
};
return adder;
}
您可以这样做:
var sum = add(1)(2)(3)(4) + 5; // results in 15
var txt = add(1)(2)(3)(4) + "hello"; // results in "10hello"
这里的关键是您需要一种方法来告诉函数停止 returning 函数。
这其实是个很好的问题...
柯里化是函数式编程语言最基本的方面之一,您可以在其中传递 return 函数。 JS在某种程度上是一种函数式编程语言,应该可以执行此操作。
所以就像你问题中的那个一样,出于这个或那个原因,人们可能想柯里化一个无限多的参数函数。
OK 让你的功能成为
function multiplyDivide (n,m,o,p){
return n * m / o * p;
}
那么实现实用程序 curry
函数以获得任何给定函数的柯里化版本的方法如下;
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(),
f = curry(multiplyDivide);
res1 = f(4,5,2,10),
res2 = f(4)(5,2,10),
res3 = f(4)(5)(2,10),
res4 = f(4)(5)(2)(10),
res5 = f(4,5)(2,10),
res6 = f(4,5)(2)(10),
res7 = f(4,5,2)(10),
res8 = f(4,5)(2,10);
console.log(res1,res2,res3,res4,res5,res6,res7,res8);
可能有更简单的方法,但这是我能想到的。
function addValues(a, b) {
if(b!=undefined)
return a + b;
return function(b) {
return a + b;
}
}
let output1 = addValues(2)(4); // 6
let output2 = addValues(2,1); // 3
console.log(output1);
console.log(output2)
function multiply(a) {
return function(b) {
return b ? multiply(a*b) : a;
}
}
console.log(multiply(2)());
console.log(multiply(2)(3)());
console.log(multiply(2)(3)(4)());
console.log(multiply(2)(3)(4)(5)());
function add() {
let args = [...arguments];
function addAll(){
let args1 = [...arguments];
return add(...args, ...args1);
}
let total = args.reduce((total, value) => total+value);
addAll.value = total;
return addAll;
}
console.log(add(2)(3)(4).value);
console.log(add(2)(3).value);