вкладення функцій
Композиція це техніка, що дозволяє вам взяти дві або більше простих функцій і об'єднати їх в одну, більш складну функцію, що виконує подфункции в логічному порядку з будь-якими даними.
Щоб отримати цей результат, ви вкладаєте одну функцію всередину іншої і виконуєте операції зовнішньої функції над результатом внутрішньої функції поки не отримаєте результат. І результат може бути різним, залежно від порядку, в якому застосовані функції.
У цьому прикладі ми задали функцію addOne (). додають одиницю до переданого аргументу і функцію timesTwo (). Множимо аргумент на два. Передаючи результат однієї функції як аргумент в іншу функцію, ми можемо бачити, як вкладення однієї функції в іншу може давати абсолютно різні результати навіть з одним значенням. Спочатку виконується внутрішня функція, а потім її результат передається зовнішньої.
імперативна композиція
Якщо ви хочете багато разів виконати послідовність операцій, вам може бути зручніше поставити нову функцію, автоматично вносить спочатку одну, а потім іншу меншу функцію. Це може виглядати приблизно так:
В даному випадку ми вручну з'єднали ці дві функції в певному порядку. Ми створили нову функцію, яка спочатку присвоює передане значення змінної holder. потім оновлює значення цієї змінної, передавши її по черзі в обидві функції і повернувши отриманий результат.
Подібним чином, якщо ми хочемо створити іншу нову функцію, що викликає дві менші функції в протилежному порядку, ми зробимо так:
Звичайно, код починає виглядати досить одноманітно. Дві наші нові композиційні функції виглядають практично однаково, за винятком порядку виклику менших функцій. Нам не вистачає DRY. Використання тимчасових змінних, які змінюють свої значення не дуже функціонально, навіть якщо вони приховані всередині створених нами композиційних функцій.
Загалом, ми можемо зробити краще.
Створення функціональної композиції
Давайте змайструємо композиційну функцію, яка може приймати існуючі функції і об'єднувати їх разом в потрібному нам порядку. Щоб зробити це послідовним чином, не граючись кожен раз з внутрішнім вмістом, ми вирішили використовувати той порядок, в якому функції передаються в якості аргументів.
У нас є два варіанти. Аргументи в обох випадках будуть функціями і вони можуть виконуватися в будь-якій послідовності. Треба визначитися, оскільки запропонована нами нова функція compose (timesTwo, addOne) може працювати як timesTwo (addOne ()). зчитуючи аргументи справа наліво або як addOne (timesTwo ()) при зчитуванні аргументів зліва направо.
Перевага виконання аргументів зліва направо полягає в тому, що вони читаються також як і звичайний текст англійською, з цієї ж причини ми назвали свою функцію timesTwoAddOne (). щоб показати, що множення в ній передує складанню. Ми всі знаємо важливість логічного іменування для отримання ясного читаного коду.
У будь-якому випадку те, що нам дійсно треба зробити, це передати спочатку все конфігураційні дані, а в кінці дані, якими ми будемо оперувати. Тому розумніше зробити нашу композиційну функцію зчитує і застосовує аргументи справа наліво.
Таким чином ми можемо створити рудиментарную функцію compose. виглядають приблизно так:
Використовуючи дуже просту функцію compose ми можемо сконструювати обидві комплексні функції з нашого прикладу більш простим способом і переконатися, що результат той же:
Хоча ця проста функція compose працює, вона не бере до уваги ряд питань, що обмежує її гнучкість і придатність. Наприклад, нам може знадобитися композиція з більш, ніж двох функцій. Також ми в ході цієї функції втрачаємо відстеження this.
Ми можемо вирішити ці проблеми, але вони не є обов'язковими для розуміння принципу роботи композиції. Замість написання власного варіанту, можливо, більш продуктивним буде успадкувати compose від однієї з бібліотек для функціонального програмування типу Ramda. в якій за замовчуванням реалізований порядок аргументів справа наліво.
Типи це ваша відповідальність
Ви не обмежені передачею чисел і навіть не обмежені збереженням одного типу змінної при передачі з однієї функції в наступну. Але ви зобов'язані забезпечити, що функції у вашій композиції готові працювати з будь-яким значенням, повернутим попередньою функцією.
Враховуйте свою аудиторію
висновок
Як і з усіма техніками функціонального програмування важливо враховувати, що ваші композиційні функції повинні бути чистими. Коротенько це означає, що при кожній передачі певного значення в функцію вона завжди повинна повертати однаковий результат і не повинна виробляти побічних ефектів, змінюючи значення у нестямі.
Композиційне вкладення може бути дуже зручним, коли у вас є набір пов'язаної функціональності, яку ви хочете застосувати до своїх даних і ви можете розбити компоненти цієї функціональності на багаторазово використовувані і легко з'єднуються функції.
Як і інші техніки функціонального програмування, композицію слід розважливо додавати в існуючий код, щоб ознайомитися з нею. Якщо ви зробите це правильно, результатом буде більш ясний, лаконічний і читається код. А хіба це не те, чого ми всі хочемо?