Функция каррирования Javascript

#javascript #currying

#javascript #каррирование

Вопрос:

У меня возникла проблема с одним из заданий в моем курсе программирования на javascript.

Назначение:

Создайте функцию с именем «calculate», которая ожидает три функции в качестве параметров и при вызове возвращает одну из этих функций в качестве результата.

Каждый раз, когда вы вызываете

 let result = calculate(add, subtract, multiply)(1,3)
  

она должна возвращать другой результат.

Я пробовал разные подходы и получал разные ошибки, такие как вычисление не является функцией или умножение не определено.

Это то, что я пробовал до сих пор:

 function add(num1, num2){
  return num1   num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(add, subtract, multiply){
  
  let randNum = Math.floor(Math.random() * 3)   1

  switch(randNum){
    case 1:
      let add = add(num1, num2)
      break;

    case 2:
      let subtract = subtract(num1, num2);
      break;

    case 3:
      let multiply = multiply(num1, num2);
      break;

  }

}

let result = calculate(add(2,4), subtract(2,4), multiply(2,4))
console.log(result);
  

Я провел некоторое исследование по каррированию, но я не вижу, в чем я ошибаюсь. Любая помощь будет с благодарностью оценена.

Комментарии:

1. «Каждый раз, когда вы call…it должен вернуть другой результат «. Это не очень четкое назначение. Что она должна вернуть в четвертый раз, если я уже вернул результаты сложения, вычитания и умножения?

2. Это (или ответ на него) на самом деле не является примером каррирования, если только у вашего инструктора нет для этого действительно излишне сложного решения. Простое решение, если используется случайность, может легко быть однострочным.

3. Может быть, я плохо перевел задание. Я думаю, что требуется, чтобы при вызове функции calculate она случайным образом выбирала одну из 3 функций, которые она получила в качестве параметров.

Ответ №1:

Это не лучший пример для обучения каррированию. Я думаю, что инструктор / курс пытается донести здесь то, что когда вы делаете:

 let result = calculate(add, subtract, multiply)(1,3)
  

вы вызываете функцию ( calculate ), которая возвращает функцию (одну из трех, которые вы ей передаете, я думаю, выбранную случайным образом, хотя назначение неясно), а затем вы вызываете эту функцию (используя (1,3) результат calculate(...) вызова.

calculate может быть однострочным:

 function calculate(...fns) {
    return fns[Math.floor(Math.random() * fns.length)];
}
  

или в ES5:

 function calculate() {
    return arguments[Math.floor(Math.random() * arguments.length)];
}
  

Живой пример:

 function add(num1, num2){
  return num1   num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(...fns) {
    return fns[Math.floor(Math.random() * fns.length)];
}

let result = calculate(add, subtract, multiply)(1,3);
console.log(result);  


Более полезным примером для обучения каррированию было бы:

 let result = calculate(add, subtract, multiply)(1)(3);
// ----------------------------------------------^^
  

Обратите внимание, что мы вызываем результат calculate with 1 , а затем вызываем результат этого with 3 . Затем calculate нужно будет обернуть выбранную функцию в другую функцию, которая собирает 1 , а затем ожидает вызова с помощью 3 :

 function calculate(...fns) {
    const fn = fns[Math.floor(Math.random() * fns.length)];
    return (a) => {
        return (b) => {
            return fn(a, b);
        };
    };
}
  

или более кратко, но менее четко:

 function calculate(...fns) {
    const fn = fns[Math.floor(Math.random() * fns.length)];
    return (a) => (b) => fn(a, b);
}
  

Живой пример:

 function add(num1, num2){
  return num1   num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(...fns) {
    const fn = fns[Math.floor(Math.random() * fns.length)];
    return (a) => (b) => fn(a, b);
}

let result = calculate(add, subtract, multiply)(1)(3);
console.log(result);  

Функция, возвращаемая calculate при вызове, запоминает a и возвращает новую функцию; эта функция при вызове получает b и вызывает fn(a, b) для получения результата.

В этом примере функция выбирается заранее, но она также может быть выбрана в конце:

 function calculate(...fns) {
    return (a) => (b) => fns[Math.floor(Math.random() * fns.length)](a, b);
}
  

Живой пример:

 function add(num1, num2){
  return num1   num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(...fns) {
    return (a) => (b) => fns[Math.floor(Math.random() * fns.length)](a, b);
}

let result = calculate(add, subtract, multiply)(1)(3);
console.log(result);  

Комментарии:

1. «или более кратко, но менее четко» , пока вы не привыкнете к функциям со стрелками. Однако даже тогда, если вложение продолжается, ясность может пострадать (по крайней мере, для меня).

Ответ №2:

Вы можете взять случайную функцию из аргументов и вернуть эту функцию для другого вызова с параметрами.

 const
    add = (a, b) => a   b,
    subtract = (a, b) => a - b,
    multiply = (a, b) => a * b,
    calculate = (...args) => args[Math.floor(Math.random() * args.length)];

let result = calculate(add, subtract, multiply)(1, 3);

console.log(result);  

Ответ №3:

calculate должен возвращать одну из функций, поэтому результат функции calculate должен вызываться с фактическими параметрами:

 function add(num1, num2){
  return num1   num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(add, subtract, multiply){

  let randNum = Math.floor(Math.random() * 3)   1

  switch(randNum){
    case 1:
      return add
      break;

    case 2:
      return subtract
      break;

    case 3:
      return multiply
      break;

  }

}

console.log(calculate(add, subtract, multiply)(2, 4));  

Комментарии:

1. Дампы кода не являются полезными ответами. Скажите, что вы сделали и почему . (Перед публикацией, а не как редактирование.)

Ответ №4:

У вас есть две проблемы в этой части кода, внутри вашей calculate функции:

   switch(randNum){
    case 1:
      let add = add(num1, num2)
      break;

    case 2:
      let subtract = subtract(num1, num2);
      break;

    case 3:
      let multiply = multiply(num1, num2);
      break;
  

  1. Вы вызываете свои математические функции ( add(num1, num2) например) внутри calculate. Это вернет число, но ожидаемое поведение заключается в том, что оно вернет функцию, чтобы вы могли вызвать ее с дополнительными параметрами:

     let result = calculate(add, subtract, multiply)(1,3)
      

  2. Ваша calculate функция не возвращает никакого значения. Таким образом, при выполнении ваших действий let result = calculate(...) результат всегда будет неопределенным.

Вместо этого ваша calculate функция должна возвращать функцию:

     function calculate(add, subtract, multiply){

      let randNum = Math.floor(Math.random() * 3)   1;

      switch(randNum){
          case 1:
          return add;

          case 2:
          return subtract;

          case 3:
          return multiply;
      }
    }
  

ДЕМОНСТРАЦИЯ:
https://jsbin.com/jiholifife/edit?js ,консоль

Обратите внимание на разницу: ваша функция calculate теперь возвращает функцию.

Это возможно из-за того, что функции в JavaScript являются объектами первого класса: функция может быть передана в качестве аргумента другим функциям, может быть возвращена другой функцией и может быть присвоена в качестве значения переменной.