Функциональное программирование: что такое Compose и Pipe в JavaScript?

Compose и Pipe - одни из самых мощных концепций функционального программирования на JavaScript. Однако их бывает сложно понять. Эта статья поможет вам лучше понять эти функции.

Написать

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

В этом примере функция g применяется к результату применения функции f к x. Как видим, композиция функций работает справа налево.

Тот же результат может быть достигнут в JavaScript с помощью compose:

ОК… действительно сбивает с толку. Давайте посмотрим на пример.

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

const user = {name: 'Gianmarco', password: 1234}
const getUserName = (user) => user.name
getUserName(user)
// 'Gianmarco'

А затем функция, которая переводит строки в верхний регистр:

const upperCase = (string) => string.toUpperCase()
upperCase('Gianmarco')
// 'GIANMARCO'

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

Мы можем использовать реализацию compose(), которую мы видели раньше:

Проблема с этой реализацией compose() заключается в том, что она принимает в качестве параметров только две функции (в нашем примере upperCase() и getUserName()).

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

const firstFour = (string) => string.substring(0,4)
firstFour(‘GIANMARCO’);
// 'GIAN'

Как мы можем составлять более двух функций одновременно?

Мы можем использовать Compose и метод reduceRight() :

const compose = (...functions) => x => functions.reduceRight((acc, fn) => fn(acc), x);

В этой реализации compose() принимает параметры отдыха (любое количество параметров - в этом примере любое количество функций) и возвращает функцию, которая принимает начальное значение x. Затем он использует метод reduceRight() для итерации справа налево по каждой функции fn в functions и, в свою очередь, применяет его к накопленному значению acc.

Проще говоря, compose() применяет справа налево любое количество функций к выходу предыдущей функции.

С помощью этой новой реализации compose() мы теперь можем создать функцию, которая получает имя пользователя, вводит его в верхний регистр и возвращает только первые четыре символа:

Круто, правда?

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

Труба

Pipe в точности похож на compose(), но работает слева направо. Я лично предпочитаю его 25, потому что вы можете думать об этом как о последовательности событий.

Если мы хотим воссоздать нашу compose() функцию выше, но с pipe(), мы можем использовать эту реализацию:

const pipe = (...functions) => x => functions.reduce((acc, fn) => fn(acc), x);

Как вы заметили, теперь мы используем reduce() вместо reduceRight(), поскольку функция выполняет итерацию слева направо.

Наш окончательный результат будет:

Как последовательность событий, pipe() применяет getUserName() к нашим исходным данным, затем применяет upperCase() к результату применения getUserName() к нашим исходным данным. Наконец, он применитfirstFour() к результату применения upperCase() к результату применения getUserName() к нашим исходным данным.

Заключение

Надеюсь, эта статья прояснила некоторые из ваших сомнений и помогла вам понять потенциал Compose и Pipe.

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