Каррирование в JavaScript и PHP

Что такое каррирование

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

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

Каррирование и замыкания

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

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

Примеры каррирования в JavaScript и PHP

Давайте начнем с JavaScript, так как в нем каррирование используется чаще.

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

function curryAdd(x) {
    return function (y) {
        return x + y
    }
}

const addFive = curryAdd(5)
console.log(addFive(3)) // Выводит 8

Данный код демонстрирует каррирование одноаргументной функции, где первый аргумент фиксирован, а второй передается при вызове каррированной функции.

  1. Функция curryAdd: Эта функция принимает один аргумент x и возвращает новую функцию, которая принимает другой аргумент y. Возвращаемая функция при вызове складывает x и y.
  2. Применение curryAdd: Мы вызываем curryAdd(5), получая новую функцию, в которой x фиксировано и равно 5.
  3. Вызов addFive(3): Здесь мы вызываем функцию addFive, переданную из curryAdd, с аргументом 3. Поскольку x уже равно 5, возвращаемое значение равно 5 + 3, то есть 8.

Сложный пример:

function curry(fn, ...args) {
    return (..._arg) => {
        return fn(...args, ..._arg)
    }
}

function multiply(a, b, c) {
    return a * b * c
}

const curriedMultiply = curry(multiply, 2)
console.log(curriedMultiply(3, 4)) // Выводит 24

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

  1. Функция curry: Эта функция принимает другую функцию fn и неопределённое количество аргументов ...args. Она возвращает новую функцию, которая может быть вызвана с дополнительными аргументами ..._arg. При вызове внутренней функции аргументы args и _arg объединяются, и результат передаётся в исходную функцию fn.
  2. Функция multiply: Это обычная функция, принимающая три аргумента и возвращающая их произведение.
  3. Применение curry к multiply: Мы вызываем функцию curry, передавая ей функцию multiply и фиксированный аргумент 2. Это возвращает новую функцию, которая ожидает два оставшихся аргумента. const curriedMultiply = curry(multiply, 2);
  4. Вызов curriedMultiply(3, 4): Мы вызываем каррированную функцию с двумя аргументами 3 и 4. Внутри curry, эти аргументы объединяются с уже заданным 2, и исходная функция multiply вызывается с тремя аргументами: 23, и 4, что возвращает 24. console.log(curriedMultiply(3, 4)); // Выводит 24

В PHP каррирование менее распространено, но его все равно можно реализовать

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

function curryMultiply($a)
{
    return function ($b) use ($a) {
        return function ($c) use ($a, $b) {
            return $a * $b * $c;
        };
    };
}

$curried = curryMultiply(2);
$curriedWithB = $curried(3);
$result = $curriedWithB(4); // Выводит 24

Здесь мы имеем функцию curryMultiply, которая принимает три аргумента: ab и c. Благодаря каррированию, мы можем передать эти аргументы последовательно, получая новую функцию на каждом этапе. Это позволяет нам создавать частично примененные функции, такие как curried, которые затем могут быть дополнены другими аргументами, как curriedWithB, и так далее.

Сложный пример:

function curry($fn, ...$args)
{
    return function (...$newArgs) use ($fn, $args) {
        return $fn(...array_merge($args, $newArgs));
    };
}

function multiply($a, $b, $c)
{
    return $a * $b * $c;
}

$curriedMultiply = curry('multiply', 2);
echo $curriedMultiply(3, 4); // Выводит 24

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

  1. Функция curry: Эта функция принимает имя функции $fn, которую нужно каррировать, и список аргументов $args, которые будут фиксированными. Она возвращает новую функцию, которая принимает дополнительные аргументы $newArgs.
  2. Функция multiply: Это простая функция, которая принимает три аргумента и возвращает их произведение.
  3. Применение curry к multiply: Мы вызываем функцию curry, передавая ей имя функции multiply и фиксированный аргумент 2. Это возвращает новую функцию, которая принимает два аргумента (поскольку первый аргумент уже задан и равен 2). $curriedMultiply = curry('multiply', 2);
  4. Вызов $curriedMultiply(3, 4): Здесь мы вызываем каррированную функцию, передавая ей два аргумента 3 и 4. Внутри каррированной функции эти аргументы объединяются с уже заданным аргументом 2, и затем вызывается исходная функция multiply с тремя аргументами 23 и 4. echo $curriedMultiply(3, 4); // Выводит 24

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

Если все равно не понятно?

Давайте рассмотрим еще один пример на языке JavaScript. Допустим, у нас есть функция sum, которая складывает два числа:

function sum(a, b) {
    return a + b
}

Если мы хотим сложить два числа 2 и 3, мы можем вызвать эту функцию следующим образом:

const result = sum(2, 3) // результат: 5

В этом примере мы передаем два аргумента - 2 и 3 - в функцию sum, которая возвращает сумму этих чисел.

function sum(a) {
    return function (b) {
        return a + b
    }
}

В этой новой версии функции sum мы принимаем только один аргумент a, а затем возвращаем функцию, которая принимает аргумент b и возвращает сумму a и b.

Теперь, чтобы сложить два числа 2 и 3 с использованием каррированной функции sum, мы вызываем ее следующим образом:

const result = sum(2)(3) // результат: 5

Здесь мы вызываем функцию sum с аргументом 2, что возвращает другую функцию, которую мы тут же вызываем с аргументом 3. Результатом является сумма 2 и 3, равная 5.

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

Написать комментарий