ДЕКЛАРАТИВНО-ФУНКЦИОНАЛЬНЫЙ
СТИЛЬ
Как инструмент для создания гибких и безопасных приложений
Цели• Писать меньше кода
• Больше бизнес логики (увеличение формализации)
• Более безопасный и качественный код
• Масштабируемость
Проблема• Типы данных, фильтрация параметров
• Возможные ошибки при работе с данными
• Концентрация на проблеме реализации, а не задаче
Общие понятия
• Императивное программирование:• Программа состоит из инструкций, которые выполняются шаг за
шагом• Есть глобальное состояние приложения• Количество состояний приложения на таком языке ограничено,
что описывается теорией конечных автоматов• Описывает что и каким образом будет выполнено• Языки:
• PHP, C, Fortran, Basic…
Общие понятия
• Декларативное программирование: (далее ДП)• Программы на таких языках обычно не имеют глобального
состояния• По сути каждое действие – программа и описывает не
последовательность инструкций, определяющих как надо вычислить, а что нужно вычислить
• Чаще всего являются интерпретируемыми• Примеры:
• Отображение HMTL страницы (описывает что нужно вывести, а не как)• SQL – описывает какие данные нужно извлечь или изменить, а не как
(СУБД сама решает как она это сделает)
Общие понятия: пример (1)
C
Haskell
Traditional
Recursive
Общие понятия
• Высокая степень абстракции• Математическая заточенность, прозрачность, простота в
формализации• Всеобщая «ленивость» операций (вычисления происходят в
момент получения данных)• Иммутабельность (отсутствие изменений в исходном контексте)• Языки:
• Haskell, Lisp, Erlang…
Mutable Immutable
Общие понятия: пример (2)
Общие понятия: пример (3)
https://gist.github.com/mdsina/b7bd90cbfeb3cabd9eb5
Общие понятия• Лямбда – некая анонимная функция, которая
полностью встраивается в тело другой функции
• Замыкание – связывает лямбду с окружающим её контекстом, что позволяет использовать переменные, описанные в глобальной области видимости контекста
Общие понятия: пример (4)
Lambda Closure
Источники данных• Контейнеры, последовательности
• Потоки, каналы получения данных
• Базы данных
• …
Данные на ввод и вывод
• Основные принципы в обработке источников данных• Берем данные из источника• Обрабатываем данные• Кладем данные в другой источник
for ($i = 0; $i < $list.getCount(); $i++) {
$list2.push( someFunc($list[$i]) );}
Разграничение проблем
• Разделение запаковки\распаковки данных из процесса
• Избавиться от необязательных переменных
• Итераторы и алгоритмы: хорошо, но не настолько
transform(getStart($list), getEnd($list), push($list2), someFunc);
Декларативный подход
• Описывает «что», а не «как»
• Пример: последовательности
$total = accumulate(inc(1),transform(function ($x) { return
$x*$x; }),repeat(10),0
);
Функторы
• Принимаем функцию, которая выполняет действия над элементами
• Нарастим используя transform
• Наращенная функция выполняется на последовательностиэлементов [1, 2, 3, 4…]
• Возвращает последовательность элементов [1, 4, 9, 16…]
function ($x) { return $x*$x; }
transform(function ($x) { return $x*$x; });
inc(1),transform(function ($x) { return $x*$x; })
transform(function ($x) { return $x*$x; });
x x*x
square
transform
1, 2, 3 , 4 1, 4, 9, 16
transform(square)
Ленивость• Бесконечные последовательности [1, 2, 3, 4…]inc(1)
• Не используется «жадно»
• Преобразуем лениво, по требованию
• Работаем с данными, которые не могут поместиться в памяти• Бесконечные последовательности• Большие данные• Запросы БД
Идея функтора• Функции на типах
• Берем любой тип T и производим наш функтор Functor: TТ.е по сути ковариантный функтор вида из C в категорию D, которое:• Сопоставляет каждому объекту объект
• Функции на функциях• Берем любую функцию f от T1 до T2• Возвращаем функцию от Functor: T1 до Functor:T2
• Сохранение идентичности
• Сохранение целостности
• Функтор – применяет функцию в упакованному значению
• Функтор – функциональный объект
Монады• Монада – аппликативный функтор
• Функции на типах• Функции на функциях: наращивание функций• Наращивание значений• Наращивание мульти-аргументных функций
• Выравнивание (превращаем двойной Functor в одинарный Functor)
• Связность (комбинация из наращивания и выравнивания)
• …
Монады• Основная задача: сделать ряд вычислений над
данными
• Основные типы:• IO – монада строгой последовательности, т.е при
связывании выполняем сначала первое, затем второе…
• Maybe – монада для отсутствующих вычислений, т.е если первое вычисление дало результат - тогда второе, иначе - ничего
• List – вычисляем результаты второй функцией от результатов первой
Что уже есть?
• https://github.com/ircmaxell/monad-php
• https://github.com/lstrojny/functional-php
• https://github.com/widmogrod/php-functional
www.functionalphp.com
• $contract->getManagementOrganization()->getShortName();call to a member function on a non-object
•
$monad = new Maybe($contract);$monad->bind(function($item) {
return $item->getManagementOrganization();})->bind(function($item) {
return $item->getShortName();});
ircmaxell/monad-php
widmogrod/php-functional
widmogrod/php-functional
widmogrod/php-functional
Положительные моменты ДП• Лямбды – универсальный инструмент дизайна
• Краткость функционального кода
• Высокая модульность
• Хорошая тестируемость
• Редуцируемость структуры ПО
• Многие задачи решаются проще, понятнее
• Больше внимания задаче, а не борьбе с языком
• Чистота функций (детерминированность)
Проблемы и особенности• Увеличенный объем копирования данных из-за
иммутабельности
• Опасные замыкания в лямбдах
• Увеличенный расход по памяти
Итог
• Удобно использовать только в достаточно специфических местах, т.к не является непосредственной частью языка
• Высокий порог вхождения из-за теоретической сложности, основанной на теории категорий и функциональном анализе
• Разделение чистого кода и кода с побочными эффектами