Сега, след като преминахме през какво е „Чиста функция“, можем да започнем да разглеждаме какво може да се постигне, като си играем с функциите и контекста.
Като започнем, нека поговорим за къри.
Дефиницията от Wikipedia е:
В „математика“ и „компютърни науки“ кърирането е техниката за преобразуване на „функция“, която приема множество „аргументи“ в поредица от функции, всяка от които приема един аргумент.
Така че по същество функцията с къри е функция, в която върнатата стойност е друга функция.
Прост пример би бил актуализирането на следния сумиращ код:
const sum = (a: number, b: number) => a + b; const result = sum(10, 20);
To:
const currySum = (a: number) => (b: number) => a + b; const result = currySum(10)(20);
В който sum
function връща вторична функция, вместо да има двата параметъра вградени и да връща резултата веднага.
Кога и защо е добре да се използва къри?
Тази техника е особено мощна, когато искаме да предоставим контекст на функция, която ще бъде изпълнена по-късно, когато информацията няма да бъде налична.
Нека да разгледаме пример от реалния живот, като използваме React, като изградим формуляр, който улавя основната информация на потребителя.
Най-лесният начин да постигнете това е като имате onChange
обратно извикване, което ще актуализира вътрешното състояние всеки път, когато потребителят напише нещо.
Проблемът е, че това не е толкова СУХО, колкото бихме могли да го приложим. С помощта на къри можем да постигнем по-просто и по-чисто решение.
Чрез създаването на функцията handleChange
, която връща обратното извикване onChange
, можем да спестим някои стъпки, тъй като всички актуализации ще бъдат обработени от същата логика.
Това е много често използвана техника във функционалното програмиране и е ключова за отключване на функционална композиция и функции от висок ред.
Нека сега да поговорим за функционалната композиция.
Композирането на функции е техниката за агрегиране на прости функции за създаване на по-стабилни. Също като карирането, крайният резултат от композирането на функция е друга функция.
Прост пример би бил да имаме sum
и aproduct
функция и искаме те да се изпълняват една след друга. Можем да ги комбинираме заедно, така че функцията за резултат винаги да е готова за използване по-късно.
const sum = (a: number) => a + 1; const product = (a: number) => a * 2; const composed = (a: number) => product(sum(a)); composed(1); // 4
С Typescript можем да изградим функция за съставяне на n
брой функции, като ги предаваме като параметри. Функцията изглежда така:
const compose = <T>(...functionList: Function[]) => (value: T) => functionList.reduceRight((result, fn) => fn(result), value);
Това води до по-ясен начин за агрегиране на двете функции, които искаме да бъдат изпълнени една след друга.
const composed = compose<number>(product, sum); composed(1); // 4
Най-изправената функция ще бъде изпълнена първа, в този случай sum
ще бъде изчислено преди product
.
Сега, след като научихме основите около къри и функционалната композиция, можем малко да повишим нивото. В следния кодов фрагмент имаме сценарий, при който искаме да актуализираме потребителската информация, която е разделена на три типа (информация, адрес и контакт).
Начинът, по който можем да изпълним функцията за актуализиране без това, което сме научили, е като опаковаме всеки резултат в следващата функция.
Грозно нали? И ако продължим да добавяме функции, ще стане по-трудно за четене. Така че нека го подобрим с това, което научихме.
След като създадем функцията composeUpdate
по състав, можем да я използваме, за да задействаме същата актуализация на множество потребителски обекти с предварително дефинираната информация като:
const user1: TUser = {...}; const user2: TUser = {...}; const updatedUser1 = composedUpdate(user1); const updatedUser2 = composedUpdate(user2);
Заключение
- Кърирането е полезна техника за споделяне на контекст между множество нива на функции.
- Композицията на функция улеснява процеса на свързване на множество процеси, които зависят от резултата от предишната стъпка.
- Идеята за съставяне на функции може да се опише като комбиниране на множество функции с кари за създаване на по-сложна, която ще бъде изпълнена по-късно.
Тази публикация в блога е част от поредицата „Функционално програмиране с Typescript“ за това как да интегрирате принципи на функционално програмиране за вашето приложение, като същевременно го поддържате безопасно за писане с Typescript.