Что такое карри?

Каррирование — это метод, позволяющий преобразовать функцию с несколькими аргументами в последовательность функций, каждая из которых принимает только один аргумент за раз. Это может быть особенно полезно в функциональном программировании и в ситуациях, когда вы хотите создавать многократно используемые функции с частичным применением.

Я пишу статью, потому что каррирование для меня было очень расплывчатым принципом. Я столкнулся с этим при использовании `react-redux`, но это использование каррированных функций, а не создание их самостоятельно. Также многие люди написали статьи на эту тему, и они приводят очень простые примеры. Это может помочь многим людям, но этого было недостаточно для меня. Итак, я повторяю один из наиболее часто используемых примеров, если вам этого достаточно; большой. Если вам нужно больше, я приведу более «реалистичный» пример, который помог мне немного лучше понять практическое использование каррирования. Давайте прыгнем в это!

Простой пример

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

1. Понимание аргументов функций. В JavaScript функции могут принимать несколько аргументов. Например, рассмотрим функцию add, которая складывает два числа:

function add(x, y) { 
  return x + y; 
}

2. Создание каррированной функции. Чтобы создать каррированную версию функции add, мы изменим ее так, чтобы она принимала по одному аргументу за раз и возвращала новую функцию, которая принимает следующий аргумент, пока не будут предоставлены все аргументы. Вот пример:

function add(x) {
  return function (y) {
    return x + y;
  };
}

3. Использование каррированной функции. Теперь вы можете использовать каррированную функцию «добавить» для добавления чисел. Вот как вы можете его использовать:

const add10 = add(10);   // Returns a new function that adds 10 to its argument
console.log(add10(3));  // Output: 13

В этом примере функция add вызывается с аргументом 10, который возвращает новую функцию. Эта новая функция add10 принимает один аргумент и добавляет к нему 10. Когда мы вызываем add10 с 3, он возвращает сумму 3 и 10, которая равна 13.

Преимущества карри

Каррирование позволяет создавать специализированные функции, частично применяя аргументы, что может быть полезно для повторного использования кода. Предоставив некоторые аргументы заранее, вы можете создавать новые функции, адаптированные к конкретным случаям использования, не повторяя один и тот же код. Это также позволяет компоновать функции, где вы можете комбинировать несколько каррированных функций для создания более сложных функций.

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

Если это все для вас понятно, вы можете перейти к заключению или прекратить чтение. Если все это все еще смутная чепуха, как это было для меня; Продолжай читать

Реалистичный пример

Давайте рассмотрим более сложный пример, чтобы продемонстрировать реальное применение каррирования. Представьте, что у нас есть функция, которая вычисляет общую стоимость продукта на основе его цены, количества и любых применимых скидок или налогов. Мы разобьем вычисление на несколько шагов, используя каррирование.

function calculateTotal(price, quantity, discount, tax) { 
 return (price * quantity) * (1 — discount) * (1 + tax); 
}

В приведенной выше функции price представляет цену за единицу, quantity — количество единиц, discount — процент скидки, а tax — процент налога. Функция вычисляет общую стоимость, умножая цену на количество, применяя скидку и добавляя налог.

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

function calculateTotalCurried(price) {
  return function(quantity) {
    return function(discount) {
      return function(tax) {
        return (price * quantity) * (1 — discount) * (1 + tax);
      };
    };
  };
};

Здесь мы преобразовали исходную функцию в каррированную версию, разделив ее на ряд функций, каждая из которых принимает по одному аргументу за раз. Каждая функция возвращает следующую функцию до тех пор, пока не будут предоставлены все аргументы, и, наконец, вычисляется общая стоимость.

Теперь давайте используем каррированную версию для расчета общей стоимости различных продуктов:

const totalCost = calculateTotalCurried(10)(5)(0.1)(0.2);
console.log(totalCost); // Output: 95

В этом примере мы передаем аргументы каррированной функции один за другим. Мы начинаем с предоставления аргумента price (10), который возвращает новую функцию. Затем мы предоставляем аргумент quantity (5), который возвращает другую функцию. Затем мы предоставляем аргумент discount (0.1) и, наконец, аргумент tax (0.2). Последний вызов функции вычисляет общую стоимость, которая равна 95.

Преимущество каррирования становится более очевидным, когда мы хотим рассчитать общую стоимость одного и того же продукта с несколькими налоговыми ставками. Мы можем создать повторно используемую функцию, используя все, кроме аргумента tax:

const calculateTotalWithTax = calculateTotalCurried(10)(5)(0.1);
const productCostWithTax1 = calculateTotalWithTax(0.2);
const productCostWithTax2 = calculateTotalWithTax(0.3);
const productCostWithTax3 = calculateTotalWithTax(0.15);

console.log(productCostWithTax1); // Output: 99
console.log(productCostWithTax2); // Output: 104.5
console.log(productCostWithTax3); // Output: 94.25

В этом сценарии мы определяем функцию calculateTotalWithTax, применяя аргументы price, quantity и discount. Затем мы повторно используем эту функцию с другими аргументами tax для расчета общей стоимости для различных налоговых процентов, используя повторное использование кода и уменьшая количество повторений.

Заключение

Каррирование обеспечивает большую гибкость и возможность повторного использования кода, позволяя создавать специализированные функции, адаптированные к конкретным случаям использования. Он способствует функциональной композиции, модульности и может упростить сложные вычисления или преобразования.

Я надеюсь, что этот пример проясняет практическое применение и преимущества каррирования в JavaScript. И приносит людям, которые борются так же, как я сделал еще некоторые разъяснения. Мне еще предстоит использовать его в проектах, над которыми я работаю. Но обязательно постараюсь больше думать об этом при написании сложных функций. И когда я использую несколько функций вместе, использование каррированной функции может оказаться полезным.