В настоящее время функциональное программирование играет важную роль в веб-разработке. Например, Reactjs и Redux популяризировали эту парадигму и сделали ее доступной для людей. это действительно здорово. У меня часто возникали проблемы с данными. С Redux данные часто представляют собой простые объекты Javascript, такие как:

Простые объекты — хороший способ начать, потому что это просто. Просто получить доступ к свойству, просто отредактировать свойство с помощью оператора распространения (я имею в виду возврат нового простого объекта с обновленным свойством).

Есть один аспект объектно-ориентированного программирования, который я сейчас упускаю, он называется инкапсуляция. Если сущность «пользователь» получена из серверной части, и серверная часть решила изменить «имя» на «имя», нам потребуется отредактировать множество файлов. Если вы используете typescript или любую типизированную систему, это довольно просто, но если у вас огромная кодовая база, это будет беспорядок. Вот почему существует инкапсуляция. В мире OO у вас есть базовый тип, к которому обращаются с помощью геттера/сеттера, это означает, что базовый тип может изменяться, не влияя на остальную часть вашего приложения. Пример:

В этом случае, даже если мой базовый тип изменится, и «firstname» станет «firstName», мне нужно просто изменить метод «getFirstname», и остальная часть моего кода не изменится.

Можем ли мы добиться того же результата с неизменяемыми структурами данных?

Эти примеры очень вдохновлены модулями Ocaml. Но я обнаружил, что он очень хорошо работает и с Javascript.

Инкапсуляция в функциональном программировании

Да, простая функция. Вместо того, чтобы ссылаться на «это», мы ссылаемся на «Пользователя», который передается в качестве параметра. Теперь, когда мы увидели общую идею, давайте добавим несколько методов:

У нас есть функция make, которая действует как конструктор. Он принимает некоторые аргументы и создает что-то типа «Пользователь». Функция «setFirstname» принимает пользователя в качестве параметра и возвращает нового пользователя с другим именем. И метод «toObject» возвращает простой объект Javascript.

Вы можете подумать: какой смысл создавать функцию «toObject», которая возвращает пользователю копию самого себя, поскольку наш пользователь уже является простым объектом Javascript?

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

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

Что, если бы я сделал:

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

В обоих случаях это сработало бы.

Супер легко печатать

Скажем, мы хотим преобразовать наше приложение в typescript. Если мы инкапсулировали наши данные в простые функции/типы данных, переход на машинописный текст становится безболезненным.

Нам просто нужно ввести наш базовый тип, чтобы сделать все наши функции явными. Мы можем вводить наши данные постепенно (модели за моделями).

В Ocaml мы называем наш базовый тип «t»:

В User.ts

Таким образом, в других файлах я могу использовать User.t для ссылки на тип пользователя. Пример:

Я даже могу использовать User.t в других моделях. Пусть говорит, что мы хотим управлять списком пользователей:

Хорошо работает с Redux

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

Это делает наши состояния, редукторы и селекторы более чистыми, поскольку обновления обрабатываются в модели. Я все еще могу изменить свой базовый тип, не меняя ничего другого :)

Легко проверить

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