ПРИЁМЫ
ФУНКЦИОНАЛЬНОГО ПРОГРАММИРОВАНИЯ
В
ОБЫЧНОМ JAVASCRIPT
КТО ВООБЩЕ Я
Паша Клименков
Senior Software Developer @ Geotab Inc.
Oakville, ON, Canada
О ЧЁМ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• Возьмём некоторые идеи из ФП
• Упростим их до предела
• Применим в JavaScript
• Посмотрим, в чём выгода
О ЧЁМ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• Возьмём некоторые идеи из ФП
• Упростим их до предела
• Применим в JavaScript
• Посмотрим, в чём выгода
О ЧЁМ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• Возьмём некоторые идеи из ФП
• Упростим их до предела
• Применим в JavaScript
• Посмотрим, в чём выгода
О ЧЁМ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• Возьмём некоторые идеи из ФП
• Упростим их до предела
• Применим в JavaScript
• Посмотрим, в чём выгода
О ЧЁМ НЕ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• ООП - дно, ФП - мессия
• Подробная инструкция к ФП
• “Монада - это моноид в категории эндофункторов”
О ЧЁМ НЕ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• ООП - дно, ФП - мессия
• Подробная инструкция к ФП
• “Монада - это моноид в категории эндофункторов”
О ЧЁМ НЕ БУДЕТ ЭТА ПРЕЗЕНТАЦИЯ
• ООП - дно, ФП - мессия
• Подробная инструкция к ФП
• “Монада - это моноид в категории эндофункторов”*
ПЛАН НА ВЕЧЕР
•Immutability
•Просто функции
•Непросто функции
•Комбинация ООП/ФП
•Функторы
•Монады
ЧТО ТАКОЕ ФП?
Такой декларативный стиль программирования, где
все функции - без побочных эффектов, а данные -
readonly.
sql, кстати, тоже декларативный
1. IMMUTABILITY
Объекты не меняют своего состояния
Переменные не меняют свои значения
IMMUTABILITY
• Оперируем только read-only данными
• Если нужно что-то изменить - создаём новый,
измененный экземпляр
ПРИМЕР
Перевод GPS координат в оконные
ПРИМЕР: ИСХОДНЫЕ ДАННЫЕ
ПРИМЕР: МЯСОРУБКА
ПРИМЕР: ЧТО МОЖЕТ МЕНЯТЬСЯ
ПРИМЕР: БЕЗ ПЕРЕМЕННЫХ
ПРИМЕР
Редактирование Entity
ПРИМЕР: КОНСТРУКТОР ENTITY
ПРИМЕР: ЧТО МОЖЕТ МЕНЯТЬСЯ
ПРИМЕР: READ-ONLY ОБЪЕКТ
КАК УМЕНЬШИТЬ СОБЛАЗН
• const либо let вместо var
• filter/map/reduce вместо for
• Object.freeze - контрольный выстрел
IMMUTABILITY: ПЛЮСЫ
• Проще понимать код
• Меньше багов
• Атомарность создания объектов (объект либо готов, либо его еще нет)
• Меньше временного связывания (когда порядок инициализации важен)
• Проще кэшировать
• Потокобезопасность*
IMMUTABILITY: МИНУСЫ
• Дополнительная нагрузка на CPU (больше действий)
• Дополнительная нагрузка на память (больше GC)
• Дополнительная нагрузка на мозг (ООП любит state)
2. ПРОСТО ФУНКЦИИ
Функции первого класса
Чистые функции
ФУНКЦИИ ПЕРВОГО КЛАССА
могут быть переданы в качестве параметра
могут быть присвоены как значения
ЧИСТЫЕ ФУНКЦИИ
• Без побочных эффектов
• Зависят только от входных параметров
(детерминированные)
ПРИМЕР: ПОБОЧНЫЕ ЭФФЕКТЫ
ПРИМЕР: НЕДЕТЕРМИНИРОВАННАЯ
ФУНКЦИЯ
ПРИМЕР: ДЕТЕРМИНИРОВАННАЯ
ФУНКЦИЯ
ПРОСТО ФУНКЦИИ: ПЛЮСЫ
• Нет побочных эффектов
• Меньше багов
• Очень просто тестировать
• Очень просто понимать
• Абсолютная потокобезопасность
• Абсолютная распараллеливаемость
ПРОСТО ФУНКЦИИ: МИНУСЫ
• Нет побочных эффектов
• Наша работа - делать побочные эффекты
• Ввод/вывод, кэш - это всё побочные эффекты
3. НЕПРОСТО ФУНКЦИИ
Композиция функций
Карринг функций
КОМПОЗИЦИЯ ФУНКЦИЙ
Композиция - умное слово, похожее на сложение.
Но для функций.
ПРИМЕР: КОМПОЗИЦИЯ
ПРИМЕР: КОМПОЗИЦИЯ
ПРИМЕР: КОМПОЗИЦИЯ
2 промежуточных массива
ПРИМЕР: КОМПОЗИЦИЯ
Один массив. Совсем один.
ПРИМЕР: ЕЩЕ КОМПОЗИЦИЯ
ПРИМЕР: ЕЩЕ КОМПОЗИЦИЯ
КАРРИНГ
Карринг (каррирование) - частичный вызов функции.
Это когда аргументов мало, а вызвать хочется
ПРИМЕР: КАРРИНГ
ПРИМЕР: КАРРИНГ
ПРИМЕР: КАРРИНГ
ПРИМЕР: КАРРИНГ
ПРИМЕР: КАРРИНГ
ПРИМЕР: КАРРИНГ
НЕПРОСТО ФУНКЦИИ: ПЛЮСЫ
• Большая гибкость в использовании функций
• Функции становятся меньше
• Мемоизация (не влезло в плюсы “просто” функций)
НЕПРОСТО ФУНКЦИИ: МИНУСЫ
• Иногда код становится загадочнее
• Можно ухудшить производительность кода
КОМБИНАЦИЯ ООП/ФП
Оболочка - ООП, ввод/вывод,
побочные эффекты
Ядро - ФП, логика, чистые
функции
Core
Shell
ОСНОВНЫЕ ПРИНЦИПЫ
• Императивная оболочка
• оболочка работает с вводом/выводом
• оболочка очень тонкая
ОСНОВНЫЕ ПРИНЦИПЫ
• Функциональное ядро
• ядро работает с immutable данными и чистыми
функциями
• ядро содержит всю логику приложения
ПРИМЕР: ДВИЖУЩИЕСЯ МАШИНКИ
ПРИМЕР: ДВИЖУЩИЕСЯ МАШИНКИ
ввод/вывод,
оболочка
ПРИМЕР: ДВИЖУЩИЕСЯ МАШИНКИ
логика,
чистые функции
ОБОЛОЧКА/ЯДРО: ПЛЮСЫ
• Основные баги будут в оболочке, которая ужата до
минимума
• Ядро очень просто тестировать. Юнит-тестов достаточно
• Оболочке достаточно нескольких интеграционных тестов
• Command query responsibility segregation из коробки
ОБОЛОЧКА/ЯДРО: МИНУСЫ
• Хоть один?
ФУНКТОРЫ
Умные контейнеры для
значений
ПРИМЕР: СКЛАДЫВАЕМ КАРТИНКИ
ПРИМЕР: СКЛАДЫВАЕМ КАРТИНКИ
ПРИМЕР: СКЛАДЫВАЕМ КАРТИНКИ
ПРИМЕР: СКЛАДЫВАЕМ КАРТИНКИ
ПРИМЕР: СКЛАДЫВАЕМ КАРТИНКИ
??? 3.png ???
ФУНКТОР
• Контейнер вокруг данных,
• который умеет применять к ним функции,
• сохраняя при этом контейнер (результат останется в
контейнере)
ФУНКТОР
• Контейнер - это массив, async, nullable - что угодно
• Внутренние данные - это числа, объекты, функторы -
всё, что угодно
• Функции применяются к данным через map()
ARRAY - ЭТО ФУНКТОР!
PROMISE - ЭТО ТОЖЕ ПОЧТИ ФУНКТОР!
НАЗАД К ПРИМЕРУ
.png
ПОЛЕЗНЫЕ ФУНКТОРЫ
• Maybe
• Either
• IO
• Writer
• State
MAYBE - ПОЧТИ КАК NULLABLE
MAYBE - ПОЧТИ КАК NULLABLE*
MAYBE - ПОЧТИ КАК NULLABLE
MAYBE ПРИМЕР
MAYBE ПРИМЕР
EITHER = LEFT ♥ RIGHT
EITHER = LEFT ♥ RIGHT
EITHER = LEFT ♥ RIGHT
EITHER = LEFT ♥ RIGHT
EITHER = LEFT ♥ RIGHT
EITHER = LEFT ♥ RIGHT
EITHER ♥ РЕЛЬСО-ОРИЕНТИРОВАННОЕ
ПРОГРАММИРОВАНИЕ
Right
Left
f(x) g(x) h(x)
Картинка и концепция взяты отсюда
И НА САМОМ ДЕЛЕ…
Классический Maybe = Just ♥ Nothing
ДРУГИЕ ФУНКТОРЫ
• IO - для ввода/вывода
• Writer - для логов
• State - для… состояний
ФУНКТОРЫ: ПЛЮСЫ
• Удобное управление вычислением
• Разделение контекста и логики
ФУНКТОРЫ: МИНУСЫ
• Крутоватая кривая обучения
• Есть соблазн вставлять функторы туда, где они не
нужны
ПРОПУЩЕННЫЕ ГЛАВЫ
• Аппликативные функторы
• Моноиды
МОНАДЫ
МОНАДЫ ПРОКЛЯТЫ. ЛИБО ВЫ ИХ НЕ
ПОНИМАЕТЕ, ЛИБО НЕ МОЖЕТЕ ОБЪЯСНИТЬ
ПРИМЕР: ВЛОЖЕННЫЕ МАССИВЫ
ПРИМЕР: ВЛОЖЕННЫЕ MAYBE
ПРИМЕР: ВЛОЖЕННЫЕ MAYBE
MAYBE СТАНЕТ МОНАДОЙ, ЕСЛИ
MAYBE СТАНЕТ МОНАДОЙ, ЕСЛИ
MAYBE СТАНЕТ МОНАДОЙ, ЕСЛИ
ВСЁ. ВЫ ЗНАЕТЕ МОНАДЫ.
Whoa!
ARRAY СТАНЕТ МОНАДОЙ, ЕСЛИ
В ECMAScript добавят flatten или flatMap (скоро)
И ДА, PROMISE - ПОЧТИ МОНАДА
ИТОГО
• Immutability - всё read-only, меньше багов
• Чистые функции - без побочных эффектов, еще меньше багов
• Композиция, карринг - переиспользуем функции
• Функторы - разделение контекста и вычислений
• Монады - “правильные” функторы
СПАСИБО!
DotsAndBrackets.com
/pasha.klimenkov
/in/pavelklimenkov
slideshare.com/pashaklimenkov
Вопросы?

Приёмы функционального программирования в обычном JavaScript