Введение в функциональное программирование

Васильев Андрей Михайлович

2021

Краткий обзор курса

Курс основан на книге Grokking Simplicity Эрика Норманда

В рамках книги автор пытается внести определение функциональному программированию и разобрать базовые техники программирования

Необходимые знания для прохождения курса:

Императивное и декларативное программирование

Пример императивного подхода

Функция для вычисления суммы чисел на JavaScript

function sum(array) {
    let result = 0;
    for(let i = 0; i < array.length; i++) {
        result += array[i];
    }
    return result;
}

Примеры императивных языков программирования

Большинство языков общего назначения являются императивными: C, C++, Python, C#, Java, JavaScript, Ruby, Kotlin, Swift, PHP, Go

С их помощью мы можем описать произвольные алгоритмы для решения любых задач

Пример декларативного подхода

Выборка данных из базы данных на языке SQL

select name,surname from students where group='IT-11-MO'

Примеры декларативных языков программирования

Большинство предметно-ориентированных языков являются декларативными: SQL, HTML, XML, Prolog, QWL, XSLT, SPARQL

Данные языки реализованы зачастую на основе императивных языков программирования

Смешение подходов

Программисты заметили, что для решения задач в конкретной предметной области объём кода на декларативном языке заметно меньше кода на императивном языке. А чем меньше понятного кода написано, тем легче понимать данный код, тем легче его поддерживать.

Варианты внедрения декларативного подхода:

Структурное, объектно-ориентированное

Все данные языки являются императивными языками программирования

Структурное и процедурное программирование

Исторически один из первых подходов к формированию программ, включает:

Объектно-ориентированное программирование

Ядром данной концепции является объект, который включает в себя данные и код, который обрабатывает эти данные

Определение функционального программирования

Рассмотрим типичные определения функционального программирования

Побочные эффекты

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

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

Чистые функции

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

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

Неверная интерпретация определения ФП

ФП — парадигма программирования при которой используются исключительно функции без побочных эффектов

Проблемы определений ФП

Программам нужны побочные эффекты

Из определения следует, что побочных эффектов следует избегать, но они являются причиной существования ПО: почтовому клиенту нужно посылать электронные письма

ФЯП удобны для работы с побочными эффектами

В функциональных ЯП разработаны специальные техники для работы с побочными эффектами, чтобы их можно было совмещать с чистыми функциями

ФЯП практичны

Определение парадигмы посредством математики может сказать, что парадигма неприменима на практике. На самом деле на ФЯП можно реализовать любое приложение и множество существующих проектов являются доказательством

ФП как набор навыков и концепций

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

Многие императивные языки вобрали в себя инструменты работы с данными из функциональных языков

Различие действий, вычислений и данных

С точки зрения ФП код можно разделить на 3 важных категории

Действия

Действия — это функции, результат работы которых зависит от времени их запуска или от количества запусков

То есть под действиями мы понимаем функции с побочными эффектами

Примеры таких функций:

Вычисления и данные

Вычисления и данные не зависят ни от времени обращения, ни от количества обращений. При любом обращении эти элементы будут возвращать корректные данные

Примеры:

Разделяем вычисления и данные

Разница между вычислениями и данными заключается в том, что вычисления могут быть выполнены, а данные нет

Работа с категориями в ФЯП

При работе над исходным кодом программисты на ФЯП различают все три категории

Определение категорий

Рассмотрим следующий пример работы веб-приложения:

  1. Пользователь помечает в интерфейсе задачу как выполненную
  2. Веб-браузер посылает сообщение на сервер, описывающий действие пользователя
  3. Сервер получает сообщение
  4. Сервер обрабатывает данные и сохраняет их в базу данных
  5. Сервер выбирает корреспондентов для отправки почтовых сообщений
  6. Сервер высылает сообщение выбранным корреспондентам

Определим для каждого шага его категорию

Определение категорий

  1. Пользователь помечает в интерфейсе задачу как выполненную

    Это действие, т.к. оно зависит от количества вызовов

  2. Веб-браузер посылает сообщение на сервер, описывающий действие пользователя

    Сообщение является данными, но их отправка — это действие

  3. Сервер получает сообщение

    Получение сообщения — это действие, т.к. зависит от количества

  4. Сервер обрабатывает данные и сохраняет их в базу данных

    Изменение состояния БД — это действие

  5. Сервер выбирает корреспондентов для отправки почтовых сообщений

    Выбор корреспондентов зависит только от события, это вычисление

  6. Сервер высылает сообщение выбранным корреспондентам

    Отправка почты — это действие

Свойства трёх категорий исходного кода

Действия

Если код зависит от времени выполнения, количества запусков или того и другого, то это действие

Вычисления

Если код занимается исключительно формированием результата на основании аргументов, то это вычисление

Данные

Данные обычно представляют собой записанные факты о произошедших событиях

Рассмотрим чек из ресторана. На данных из чека можно

Инструменты ФЯП

Действия

Вычисления

Данные

Зачем заниматься категоризацией?

ФЯП по своей природе гораздо лучше работают в рамках распределённых систем по сравнению с другими языками

Большинство современных приложений — распределённые

Проблемы сетевых распределённых приложений:

Т.е. возникают проблемы, связанные с моделированием изменений во времени: проблемы от количества вызовов и от времени вызовов

Чем категории могут помочь?

Данные и вычисления не зависят от количества обращений, ни от времени их выполнения. Чем больше данных и вычислений в приложении и чем меньше действий, тем меньше мест в приложении, где может возникнуть проблемы распределённых приложений

Проблемы останутся в действиях, но мы их явно идентифицировали в приложении, поэтому можем применить к ним техники управления указанными проблемами

Что такое функциональное мышление

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

В рамках курса (и книги) постараемся овладеть этими инструментами, чтобы успешно применять их на практике

Базовые идеи ФП:

Правила выбора идей и навыков

Данные правила были использованы для выбора идей для книги, и следовательно будут рассмотены в курсе

  1. Они не должны быть основаны на уникальных особенностях функциональных языков программирования. Пример: мощная система типов, встроенные неизменяемые типы и т.п.
  2. Навыки должны быть применимы на практике и приносить пользу при программировании
  3. Идеи и навыки должны быть применимы к коду в любой ситуации, не обязательно начинать новый проект на ФЯП, чтобы применить эти навыки и идеи