Как вывести функцию на неизвестное количество параметров
Скажем, у меня есть функция под названием multiplyDivide
Если бы я позвонил multiplyDivide(2)(3)(4)(6)
это было бы эквивалентно 2 * 3 / 4 * 6
,
Обновление: возможно ли написать такую функцию, если я не знаю заранее, сколько параметров я буду принимать? Например, я мог бы иметь multiplyDivide(1)(2)
или же multiplyDivide(1)(2)(3)(4)...(n-1)(n)
7 ответов
Почему это должно быть карри? Разве это не было бы намного проще просто "перегрузить" функцию, предоставляя n
аргументы?
function multiplyDivide() {
var result = arguments[0];
for (var i = 1; i < arguments.length; i++) {
result = (i % 2) ? (result * arguments[i]) : (result / arguments[i]);
}
return result;
}
console.log(multiplyDivide(2, 3, 4, 6)); //9
console.log(multiplyDivide(5, 4, 2, 3, 3, 5, 1)); //50
Это в некотором роде возможно, но вам нужно определить условие завершения, потому что проблема по сути та же, что и при написании рекурсивной функции. Функция нуждается в способе сообщить погоду, она должна возвратить функцию или значение.
Как вы сигнализируете о необходимости ценностей, зависит от вас. Один из способов сделать это - проверить, передан ли аргумент:
// 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 функции являются объектами, вы также можете реализовать метод получения значений как статический метод. Он не будет чисто функциональным, но сделает 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"
Ключевым моментом здесь является то, что вам нужен способ сообщить функции прекратить возвращать функции.
Вы имеете в виду что-то подобное?
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));
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);
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)
На самом деле это очень хороший вопрос...
Карринг является одним из самых фундаментальных аспектов функциональных языков программирования, где вы можете передавать и возвращать функции. JS, являющийся функциональным языком программирования на каком-то уровне, должен уметь выполнять эту операцию.
Так что, так же как и в вашем вопросе, вы можете захотеть добавить неограниченное количество аргументов по тем или иным причинам.
ОК, пусть ваша функция будет
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);
Там могут быть более простые способы, но это то, что я мог придумать.