Короткий вступ до pipe () та compose () у JavaScript

Функціональне програмування було для мене цілком привабливою подорожжю. Ця публікація та подібні до неї публікації є спробою поділитися своїми думками та перспективами, коли я ходжу по нових країнах функціонального програмування.

Ramda була моєю бібліотекою FP через те, наскільки простіше робить функціональне програмування в JavaScript. Дуже рекомендую.

Труба

Концепція pipeпростої - вона поєднує в собі nфункції. Це труба, що протікає зліва направо, викликаючи кожну функцію з результатом останньої.

Давайте напишемо функцію, яка повертає чиюсь name.

getName = (person) => person.name; getName({ name: 'Buckethead' }); // 'Buckethead' 

Давайте напишемо функцію, яка пише великі рядки рядків.

uppercase = (string) => string.toUpperCase(); uppercase('Buckethead'); // 'BUCKETHEAD' 

Отже, якщо ми хотіли отримати та використати велике personім’я, ми могли б зробити це:

name = getName({ name: 'Buckethead' }); uppercase(name); // 'BUCKETHEAD' 

Це добре, але давайте усунемо цю проміжну змінну name.

uppercase(getName({ name: 'Buckethead' })); 

Краще, але я не люблю це гніздування. Може бути занадто тісно. Що робити, якщо ми хочемо додати функцію, яка отримує перші 6 символів рядка?

get6Characters = (string) => string.substring(0, 6); get6Characters('Buckethead'); // 'Bucket' 

В результаті:

get6Characters(uppercase(getName({ name: 'Buckethead' }))); // 'BUCKET'; 

Давайте зійдемо з розуму і додамо функцію для зворотних рядків.

reverse = (string) => string .split('') .reverse() .join(''); reverse('Buckethead'); // 'daehtekcuB' 

Тепер ми маємо:

reverse(get6Characters(uppercase(getName({ name: 'Buckethead' })))); // 'TEKCUB' 

Це може отримати трохи ... багато.

Труба на допомогу!

Замість того, щоб глушити функції всередині функцій або створювати купу проміжних змінних, давайте pipeвсі речі!

pipe( getName, uppercase, get6Characters, reverse )({ name: 'Buckethead' }); // 'TEKCUB' 

Чисте мистецтво. Це як список завдань!

Давайте переступимо через це.

Для демонстраційних цілей я буду використовувати pipeреалізацію з однієї зі статей функціонального програмування Еріка Елліотта.

pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); 

Я люблю цей маленький однокласник.

Використовуючи параметри відпочинку , див. Мою статтю про те, що ми можемо конвеювати nфункції. Кожна функція бере вихід попередньої, і все це зменшується ? до єдиного значення.

І ви можете використовувати його так само, як ми використовували вище.

pipe( getName, uppercase, get6Characters, reverse )({ name: 'Buckethead' }); // 'TEKCUB' 

Я розгорну pipeі додам кілька налагоджувальних операторів, і ми будемо переходити за рядком.

pipe = (...functions) => (value) => { debugger; return functions.reduce((currentValue, currentFunction) => { debugger; return currentFunction(currentValue); }, value); }; 

Зателефонуйте pipeна нашому прикладі і нехай розкриються дива.

Перевірте локальні змінні. functionsє масивом з 4 функцій і valueє { name: 'Buckethead' }.

Оскільки ми використовували параметри відпочинку , pipeдозволяє використовувати будь-яку кількість функцій. Він просто прокрутить і викличе кожного.

На наступному налагоджувачі ми всередині reduce. Тут currentValueпередається currentFunctionі повертається.

Ми бачимо результат тому, 'Buckethead'що currentFunctionповертає .nameвластивість будь-якого об’єкта. Це буде повернуто reduce, тобто currentValueнаступного разу це стане новим . Давайте натиснемо наступний налагоджувач і подивимось.

Тепер currentValueце , ‘Buckethead’тому що це те , що отримав повернувся в минулий раз. currentFunctionє uppercase, так 'BUCKETHEAD'буде наступним currentValue.

Та сама ідея, вирвіть ‘BUCKETHEAD’перші 6 символів і передайте їх наступній функції.

reverse(‘.aedi emaS’)

І готово!

А як щодо compose ()?

Це просто pipeв іншому напрямку.

Отже, якщо ви хочете отримати той самий результат, що і pipeвище, ви зробите все навпаки.

compose( reverse, get6Characters, uppercase, getName )({ name: 'Buckethead' }); 

Зверніть увагу, як getNameостанній у ланцюжку та reverseперший?

Ось швидка реалізація compose, знову ж ввічливості Чарівного Еріка Елліотта, з тієї ж статті.

compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x); 

Я залишу розширення цієї функції за допомогою debuggers як вправу для вас. Пограйте з ним, використовуйте його, цінуйте це. І головне, отримуйте задоволення!