💻
Подготовка к собеседованию
  • Оглавление
  • Архитектурные вопросы
    • Как избавиться от монолитности приложения?
    • Модульность VS Микросервисы
    • Микросервисы VS Монолит
    • Web services, RESTfull, SOAP
    • Распределенные системы
    • Вопросы по микросервисам
    • Разложение монолита
  • Языки программирования
    • Императивные и декларативные языки программирования
    • Функциональное программирование
  • Коммуникация
    • Основы WEB
    • Уровни модели OSI
    • IP
    • TCP
    • UDP
    • TCP и UDP – в чем разница?
    • TCP/IP
    • Приложения TCP / IP
    • ICMP
    • HTTP
    • HTTP/1.1 vs HTTP/2
    • Разница между HTTP и HTTPS
    • URL и URI - в чем различие?
    • SSL
    • TLS
    • Web Sockets
    • SOAP vs REST vs GraphQL vs RPC
    • DNS
    • Как работает интернет
  • среда выполнения
    • Процессы, потоки,нити
  • Алгоритмы
    • Алгоритмы и структуры данных
  • БД
    • Основы БД
    • Транзакции
    • Нормализация БД
    • SQL
  • Брокеры сообщений
    • Введение в kafka
    • kafka
    • 5 вещей, о которых должен знать любой разработчик Apache Kafka
  • Парадигмы проектирования
    • 10 важнейших принципов разработки программного обеспечения
    • Принципы для разработки: KISS, DRY, YAGNI, BDUF, SOLID, APO и бритва Оккама
  • Highload
    • За двумя зайцами погонишься — чеклист для HighLoad системы гуглить будешь
Powered by GitBook
On this page

Was this helpful?

  1. Языки программирования

Функциональное программирование

PreviousИмперативные и декларативные языки программированияNextОсновы WEB

Last updated 4 years ago

Was this helpful?

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

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

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

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

Плюсы:

  1. Код станет более лаконичным и выразительным. «Выразительность» можно определить как количество идей на единицу кода, и в целом функциональные языки, будучи более высокоуровневыми, оказываются и более выразительными. Например, преобразование каждого элемента в массиве или списке реализуется функциональным однострочником (используя map/foreach/whatever и анонимную функцию), в то время как в императивном стиле пришлось бы организовывать цикл, объявлять переменную для счётчика или итератора и использовать явное присваивание.

  2. Декомпозиция кода будет происходить более естественно. Принцип «Разделяй и властвуй» уже прочно закрепился в разработке и является базовым принципом борьбы со сложностью ПО. В функциональном программировании эти мелкие задачи выражаются как небольшие вспомогательные функции, каждая из которых делает своё дело и её работу можно описать одним коротким предложением. А построение итогового результата — это композиция таких функций. Конечно, разбить код на отдельные переиспользуемые части можно и в ООП, и в чисто императивном низкоуровневом языке типа C, и для этого уже есть известные принципы типа SOLID и GoF-паттерны, но, когда сам язык заставляет программиста думать в терминах функций, декомпозиция кода происходит гораздо более естественно.

  3. Побочные эффекты будут отделены от чистых функций. Чистая функция — это функция в математическом смысле, результат работы которой зависит только от входных данных. В ходе вычисления такой функции не происходит ничего лишнего: не меняются значения переменных, ничего не читается и не печатается, не пишется в БД и не выполняются запросы к внешним сервисам.

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

Минусы:

1. На чистых функциональных языках не существует эффективного неупорядоченного словаря и множества. С 90х годов использование словарей в разработке побило все рекорды. Словари теперь—стандартная коллекция, которую каждый разработчик ожидает найти в своей стандартной библиотеке. Чисто функциональные словари обычно примерно в 10 раз медленнее, чем хорошо реализованные хэш-таблицы, и я видел случаи, когда разница достигала 40 раз. Для некоторых приложений это непозволительно медленно.

2. Не существует чисто функциональных потокобезопасных коллекций

По определению, неизменяемые коллекции не могут поддерживать мутабельность, в том числе и потокобезопасную. Так что, если вы хотите shared изменяемую коллекцию (такую как in-memory базу данных), то чисто функционального решения не существует.

3. Большинство алгоритмов на графах выглядят хуже и работают намного медленнее, если написаны в функциональном стиле

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

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

5. Как оказывается, все существующие реализации функциональных языков—как чистых, так и нечистых (impure)—спроектированы так, что аллоцируют слишком много памяти

6. Чистое функциональное программирование хорошо для параллелизма в теории, но не очень хорошо с точки зрения производительности на практике, а высокая производительность на практике—единственная настоящая задача параллелизма Сегодня есть две причины писать параллельные программы. Первая—это писать объективно быстрые решения. Вторая—делать медленные решения не такими медленными. В большинстве случаев параллельное программирование на функциональном языке—вариация второй причины. Почти никто в среде высокопроизводительных вычислений (high performance computing), то есть на суперкомпьютерах, не запускает напрямую функциональный код. Если разработчик на функциональном языке параллелизует программу, в большинстве случаев он делает это не для того, чтоб добиться отличной абсолютной производительности, а чтоб улучшить ту скорость, что у него есть.

7. О функциональном программировании циркулирует множество ложной информации Долгое время сообщество функционального программирования потрясало замечательно короткими реализациями алгоритмов решета Эратосфена и quicksort. Их даже годами преподавали студентам. И только спустя многие годы пришло понимание, что эти реализации не соответствуют исходным алгоритмам. Мелисса О'Нил (Melissa O’Neill) даже опубликовала , исправляющую решето Эратосфена в Хаскеле. В частности, ее настоящее решето требует в сто раз больше кода, чем ошибочная оригинальная версия. То же справедливо и для quicksort'а, где «элегантная» двухстрочная версия на Хаскеле более чем в 1000 раз медленнее версии Сэджвика на C, потому что Хаскель делает глубокую копию списков на каждом вызове quicksort'а, портя к чертям асимптотическую сложность оригинального алгоритма Хоара.

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