如何在未知数量的参数上curry一个函数

How to curry a function across an unknown number of parameters

本文关键字:函数 一个 curry 未知数 参数      更新时间:2023-09-26

假设我有一个函数叫multiplyDivide

如果我叫multiplyDivide(2)(3)(4)(6),它就等于2 * 3 / 4 * 6

更新:有没有可能写出这样一个函数如果我事先不知道要取多少参数呢?例如,我可以输入multiplyDivide(1)(2)multiplyDivide(1)(2)(3)(4)...(n-1)(n)

这是可能的,但你需要定义终止条件,因为这个问题本质上和写递归函数是一样的。函数需要一种方法来判断它应该返回一个函数还是一个值。

如何表示需要值取决于你自己。一种方法是检查是否传递了参数:

// 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)();

否则它将返回一个函数,你可以一直调用:

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"

这里的关键是需要一种方法来告诉函数停止返回函数。

使用函数式方法,您可以创建一个为另一个函数"处理"参数的函数。您需要一种方法来告诉函数返回值,因此在本例中,调用函数而不传递任何参数将返回结果:

function curry(fn, ...values) {
    return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}

这个函数最酷的地方是你可以传递多个参数和/或继续调用函数(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));

你的意思是这样吗?

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));

这其实是一个非常好的问题…

柯里化是函数式编程语言中最基本的方面之一,你可以在其中传递和返回函数。JS在某种程度上是一种函数式编程语言,应该能够执行此操作。

所以就像你的问题一样,人们可能会因为这样或那样的原因想要curry一个无限多参数的函数。

让你的函数为

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);