Функціональний словник програмування: 25 FP термінів для розробників

Чиста функція, незмінність, функції вищого порядку, монади, каррування і словник функціонального програмування.

Функціональне програмування перейшло від академічної цікавості до загальної практики. Незалежно від того, працюєте ви на TypeScript, Scala, Haskell або навіть пишете гачки React, ви щодня стикаєтеся з концепціями FP. Виклик для багатьох розробників — особливо тих, що працюють в міжнародних командах — полягає в тому, що функціональне програмування має свій власний щільний словник. Нерозуміння одного терміну, наприклад, «монада» або «референтна прозорість» може зробити перегляд коду схожим на іспит з іноземної мови. Цей посібник містить 15 основних термінів з FP з визначеннями простою англійською мовою і прикладами реальних розмов, щоб ви могли безпечно брати участь у технічних обговореннях.


Основні праці: «Функціональна логіка

Ці терміни з’являються майже в кожній обговоренні FP. Якщо нічого іншого не навчишся, то навчись цих.

** Чиста функція ** — функція, яка завжди повертає той самий вивід для того ж вводу і не спричиняє ніяких спостережуваних змін поза собою. Без мережевих викликів, записів файлів, мутацій.

“Ми повинні переробити цей рівень обслуговування. Більшість з цих функцій не є чистими — вони читаються з глобального конфігурації об’єкта, що робить їх неможливим перевірити в ізоляції»

“Я переписав розрахунок ціни як чисту функцію. Тепер тести блоків працюють в мілісекундах і нам не потрібно нічого насміхатися»

** Побічний ефект ** — будь- яка спостережувана взаємодія функції з зовнішнім світом: запис до бази даних, реєстрація у консолі, зміна змінної за межами її обсягу або виконання запиту HTTP.

«Вага була викликана побічною дією в мапері — він безшумно мутував вхідний масив замість того, щоб повернути новий.»

«У нашому FP шарі ми намагаємося відштовхнути всі побічні ефекти до країв застосування. Основна логіка бізнесу залишається чистою»

** Незмінність ** — принцип, за якого після створення структури даних її неможливо змінити. Замість зміни об’ єкта, ви створюєте новий об’ єкт з оновленими значеннями.

«Ми перейшли на незмінні структури даних для нашого магазину Redux. Зневадження стало набагато простіше — ми могли відтворити кожен перехід стану»

«Модифікатор readonly TypeScript вимагає незмінності під час компіляції, що є хорошим початком, але не глибоко заморожує вкладені об’єкти»

** Посилальна прозорість ** — вираз є посилально прозорим, якщо його можна замінити на його оцінюваний результат без зміни поведінки програми. Чистий виклик функції є посиланням прозорим; функція, яка читає поточний час, не є.

“Якщо функція є посилально прозорою, ви можете безпечно її замінити. Результат завжди однаковий для тих же аргументів.»

«Ця функція не є посилально прозорою — вона залежить від Date.now(), тому викликаючи її двічі з тим же вхідним значенням, отримуємо різні виходи»


Функціонує як громадянин першого класу

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

** Функція першого класу ** — функція, яку можна призначити змінній, передати як аргумент або повернути з іншої функції, так само як і будь- яке інше значення.

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

** Функція вищого порядку ** — функція, яка приймає одну або більше функцій як аргументи, повертає функцію або обидві.

«Наша withRetry корисність є функцією вищого порядку. Ви передаєте йому будь-яку асинхронну функцію і він обгортає її з логікою повторних спроб»

«Якщо ви звикнете до функцій вищого порядку, шаблони, такі як середнє програмне забезпечення і декоратори, починають відчуватися очевидними»

** map / filter / reduce ** — три фундаментальні функції вищого порядку. map перетворює кожен елемент збірки, filter вибирає елементи, що відповідають предикату, і reduce (також званий fold ) згортає збірку до одного накопиченого значення.

«Замініть цю петлю for петлею map і filter — це буде в половину рядків і набагато більш читабельно»

“Я використовував reduce для побудови пошукового об’єкта з масиву. Один прохід, ніяких побічних ефектів»

** Currying ** — перетворення функції, яка приймає декілька аргументів, у послідовність функцій, кожна з яких приймає один аргумент. Названо на честь математика Гаскела Каррі.

“Функція add є каррованим, тому add(2) повертає нову функцію, що очікує на другий аргумент. Ви можете частково спеціалізуватися на цьому»

«Каррі — це механізм; часткове застосування — це випадок використання. Вони пов’язані, але не одна і та ж річ»

** Часткове застосування ** — встановлення кількості аргументів до функції, що створює нову функцію з меншою арітією. На відміну від каррування, вона не вимагає зменшення до одноаргументних функцій.

«Ми використовуємо partial з Ramda, щоб випікати базовий URL в наш API helper. Кожна функція маршруту тоді потребує тільки шляху»

“Часткове застосування чудово підходить для налаштування. Ви встановите інваріантні параметри один раз і повторно використовувати спеціалізовану функцію всюди»


Об’єднання і абстрагування: композиція і шаблони

** Складання функцій ** — поєднання двох або більше функцій так, щоб вивід однієї з них став вхідною інформацією для наступної. Математично записується як f ∘ g, що означає «застосувати g спочатку, а потім f».

«Замість вкладення функції виклику п’ять рівнів глибини, використовуйте compose або pipe для читання перетворення як лінійного конвеєра»

«Композиція функцій є відповіддю FP на спадковість. Збудуйте складну поведінку з маленьких, повторно використовуваних частин»

** Безточковий стиль ** — написання визначення функції без явного згадування аргументів (« точок »). Функція визначається чисто з точки зору композиції і функцій вищого порядку.

«Ця лямбда може бути написана без точок: замість x => toUpperCase(x) просто передайте toUpperCase безпосередньо»

«Стиль без точок елегантний, але може пошкодити читабельність, якщо надмірно використовувати. Упевніться, що команда з ним комфортно, перш ніж йти на все»

** Хвостова рекурсія ** — форма рекурсії, у якій рекурсивний виклик є останньою операцією у функції. Хвостова рекурсивна функція може бути оптимізована за часом виконання в петлю, уникаючи переповнення стека для великих вхідних даних.

“Наївна рекурсивна версія розриває стек на великі списки. Переписати його як хвостову рекурсію і оптимізатор перетворить його в ітерацію»

JavaScript не оптимізує хвостові виклики в більшості рушіїв, тому на практиці ми використовуємо трамплін або просто ітерацію

** Легке оцінювання** — відкладання обчислення значення до моменту, коли воно буде дійсно потрібне. Це контрастує з охочим (суворим) оцінюванням, яке обчислює значення негайно.

“З лінивим оцінюванням, ми можемо представляти нескінченні послідовності. Ми обчислюємо тільки стільки елементів, скільки споживач фактично запитує»

“RxJS Observables за замовчуванням є лінивим — нічого не запускається, поки ви не підпишетеся. Це ключова відмінність від Promises»


Основні види: монети та монети

Ці терміни походять з теорії категорій і лякають багатьох розробників. Концепції насправді простіші, ніж їхні назви.

** Функтор ** — будь- яка структура, яку можна перенести. На практиці, функтор є контейнером, який реалізує метод map, який підкоряється двом законам: ідентичності і композиції. Масиви в JavaScript є функторами.

«Масив є найпростішим функтором. map застосовує функцію до кожного значення, зберігаючи структуру контейнера.»

«Ми написали тип Result, який є функтором. Ви можете безпечно переписувати його — якщо він містить помилку, переписування не є операцією»

Monad — функтор з двома додатковими операціями: of (обгортання значення) і flatMap / chain (відображення з функцією, яка сама повертає обгорнуте значення, а потім сплощення). Монади нададуть вам змогу послідовно виконувати обчислення, які потребують контексту — нульовість, помилки, асинхронність.

Три найкорисніші монади для розробників веб- програм:

  • ** Можливо (Параметри) ** — позначає значення, яке може бути відсутнім. Виключає перевірки нульових значень, роблячи відсутність значення явним у типі.

«Ми обгорнули наші нульові результати DB в Maybe. Тепер весь конвеєр є нуль-безпечним без жодної перевірки if»

  • ** Або** — позначає обчислення, яке може закінчитися успіхом (праворуч) або невдачею (ліворуч). Дозволяє обробку помилок без винятків.

“Замість того, щоб кинути, перевірка повертає Either. Викликач може fold над ним, щоб обробляти обидві гілки»

  • IO — обгортає обчислення, що виконуються з боку, відкладаючи його і роблячи явним у підписі типу, що функція розмовляє з зовнішнім світом.

“Монада IO робить побічні ефекти цінностями першого класу. Ви можете складати IO дії без їхнього запуску»


Як використовувати їх у розмові

** Перегляд коду: ** “Ця функція не чиста — вона мутує об’ єкт user, який передається. Чи можемо ми повернути новий об’єкт замість цього і зберегти наші дані незмінними по всьому конвеєру?»

** Обговорення архітектури: ** “Проблема в тому, що побічні ефекти розкидані повсюди. Якщо ми підштовхнемо їх до межі і збережемо логіку домену референтно прозорою, ми зможемо перевірити кожне бізнес-правило без насмішок над інфраструктурою»

Приєднання до команди: “Уявіть монаду як коробку з контрактом. Коробка Maybe каже: «Я можу бути порожній, але ви все ще можете безпечно відобразити на мені.’ Ви ніколи не повинні перевіряти на нуль — коробка обробляє це»

** Коментар до запиту на витяг: ** “Нічого не скажеш про каррі. Одна пропозиція: складений конвеєр на рядку 47 читає справа наліво, тому що ви використовували compose. Розглянемо pipe замість цього, щоб він читав в порядку, в якому дані протікають через нього»


Краткий справочник

TermOne-line definition
Pure functionSame input → same output, no side effects
Side effectAny interaction with the outside world
ImmutabilityData cannot be changed after creation
Referential transparencyExpression can be replaced by its value safely
Higher-order functionTakes or returns a function
CurryingMulti-argument function → chain of single-argument functions
Partial applicationPre-fill some arguments, return a specialised function
Function compositionChain functions so output of one feeds input of the next
FunctorContainer that supports map
MonadFunctor that supports flatMap for sequencing contextual computations

Поширені запитання

Про що ця стаття "Функціональний словник програмування: 25 FP термінів для розробників"?

Чиста функція, незмінність, функції вищого порядку, монади, каррування і словник функціонального програмування.

Чи безкоштовна ця стаття?

Так. Усі статті на CoderSlingo, включно з цією, доступні безкоштовно без реєстрації.

Скільки часу займає читання "Функціональний словник програмування: 25 FP термінів для розробників"?

Приблизно 9 min.