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

По определению Википедии чистая функция это:

В компьютерном программировании чистая функция — это функция, обладающая следующими свойствами:

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

функция приложение не имеет побочных эффектов (нет мутации локальных статических переменных, нелокальных переменных, изменяемых ссылочных аргументов или потоков ввода/вывода).

Итак, теперь, когда у нас есть представление о том, что это значит, мы можем начать с нескольких примеров.

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

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

Еще один хороший пример — Date.now, который всегда возвращает время между 1 января 1970 года и настоящим моментом в миллисекундах. Независимо от того, сколько раз вы запускаете его, вы никогда не получите тот же результат.

Тогда какой хороший пример функции соответствует этому правилу?

Я не хочу уподобляться ленивому учителю, который просто говорит, что (x, y) => x + y — это наглядный пример, потому что… ну, сколько раз вы будете писать такую ​​функцию, верно?

Вместо этого мы можем сделать это с помощью React. Примером может служить функциональный компонент, который:

  1. Не подключен ни к одному магазину.
  2. Не использует контекстный хук.
  3. Не использует изменяющую статическую переменную.

Что-то вроде:

Эти типы компонентов называются презентационными или простыми компонентами.

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

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

Один из способов написать это — иметь функцию addProduct, которая будет получать и корзину, и товар. Затем обновите корзину последним продуктом, поместив его в массив products и обновив totalPrice, просуммировав цену продукта.

Это нарушает правила чистой функции, поскольку вызывает побочный эффект для параметра basket путем обновления атрибутов productsи totalPrice. Распечатав результат этой функции, мы получим:

Итак, как мы можем преобразовать его в чистую функцию? Один из способов сделать это — сгенерировать новый объект корзины в функции addProduct и вместо этого вернуть его.

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

Как мы видим здесь, исходный объект basket не изменился, вместо этого у нас есть отдельный экземпляр с обновленными значениями.

Почему важны чистые функции?

  1. Чистые функции легче отлаживать и тестировать, потому что для одних и тех же входных данных они всегда должны возвращать один и тот же результат.
  2. Избегая побочных эффектов, вы можете обойти условия гонки и загрязнение объектов, которые могут вызвать трудно отслеживаемые ошибки.
  3. Чистые функции — это ворота к другим методам функционального программирования, таким как каррирование, функции высокого порядка и композиция объектов.

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

Введение | "Следующий >"