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

Clojure, Elixir, Elm, F#, Haskell, Idris и Scala — это те языки, которые чаще всего можно увидеть среди рекомендованных к изучению для функционального программирования (ФП). Им учатся сегодня и они еще долгие годы не растеряют своей популярности. Haskell — это наиболее ранний язык, но со временем более поздние, такие как Clojure, переплелись с ним, образуя общую картину эволюции ФП. Так какие же задачи решает этот отдельный класс языков программирования?

Что такое ФП

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

Термин «функциональное программирование» уходит корнями к способу программирования, который базируется на создании чистых функций. Основой всех языков ФП является лямбда-исчисление (Lambda Calculus, также обозначается как λ-исчисление), которое описывается как «самый маленький универсальный язык программирования в мире». Соответственно, ФП состоит из математических функций, которым для проведения вычислений требуются условные выражения и рекурсия.

ФП характеризуют следующие особенности:

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

ФП состоит из математических функций

ФП основано на Lambda Calculus. Разработка концепции принадлежит авторству Алонза Черча, она появилась на свет в 1936 г., но поскольку в те далекие времена компьютеров не существовало, она носила чисто теоретический характер. Так было до 1960 г., когда американский ученый-компьютерщик Джон Маккарти опубликовал работу «Рекурсивные функции символьных выражений и их вычисление на машине». В результате его исследования появился первый язык ФП: LISP. У LISP имеются ответвления, в том числе Common Lisp, Scheme и elisp, а также Clojure, последний пользуется большой популярностью и в наше время.

Как уже говорилось, базовые принципы программирования LISP заложили основу современного ФП. Вот некоторые из них:

  • применение замыканий для реализации статической области видимости. Например, функция f в выражении let x = 3 in f = λ y. x + y не является закрытой, поскольку имеет свободную переменную x. Для того, чтобы задействовать ее, она должна быть связана со средой, которая сообщает значение x. Функция, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции в окружающем коде и не являющиеся ее параметрами, называется замыканием;
  • условное выражение и его использование для написания рекурсивных функций. Этот принцип связан с «ленивым» порядком вычисления выражений;
  • применение высокоуровневых операций в списке, такие как функция mapcar.

LISP стал первым языком, где появилась функция «сборка мусора». Это важная функция для функциональных языков, потому что в отличие от императивных языков они генерируют большее количество промежуточных данных («мусорных данных»).

Спустя почти два десятилетия, в 1978-м, в развитии ФП состоялся новый прорыв. Исследователи из Эдинбургского университета изобрели метаязык (Metalanguage), который предназначался для работы с их автоматической системой доказательства теорем (LCF). Как позже выяснилось, его можно применять в качестве языка программирования общего назначения. Метаязык имеет две версии: Standard ML of New Jersey (бесплатный компилятор с открытым кодом и среда программирования для языка программирования Standard ML) и CAML. Эдинбург преподнес ФП еще один подарок — язык Hope. Источником названия послужил Hope Park Square, где находился Эдинбургский отдел компьютерных наук. Hope — первый язык, использующий вызов по шаблону.

Язык Haskell был назван в честь логика Хаскелла Карри. Формулирование стандартов и задач языка состоялось в 1987 г. в ходе конференции по функциональным языкам программирования и компьютерной архитектуре в Орегоне. Первая версия Haskell 1.0 появилась в 1990 г. Версия языка Haskell 2010 была объявлена в конце 2009 г., в 2020 г. ожидается выход новой версии. Haskell стал парадигмой современных функциональных языков, отличающихся от других видов языков функциями высшего порядка, выводом типов, «ленивым» порядком вычислений и пользовательскими типами данных.

Функции высшего порядка принимают другие функции в качестве аргументов или возвращают их в качестве результатов. Они учитывают случаи, которые называются каррированием, когда функция от нескольких аргументов преобразуется в функцию (или набор функций) от одного аргумента. Это позволяет каждому приложению возвращать новую функцию, а затем принимать следующий аргумент. В Haskell большое значение имеют «ленивые» вычисления. В отличие от «строгих» вычислений они позволяют кодировать то, что требуется в первую очередь.

В 2009 г. сформировалась концепция Haskell Platform — стандартного дистрибутива языка, включающего кроме компилятора (GHC), также дополнительный инструментарий (систему сборки и развертывания пакетов Cabal) и набор популярных библиотек. Сейчас Haskell Platform — это рекомендованный базовый дистрибутив для разработчиков. Готовые сборки Haskell Platform доступны для Windows, MacOS X и ряда дистрибутивов Linux.

Основные современные языки ФП

Haskell — наиболее известный среди языков ФП. Вероятно, это связано с его богатой историей. Он также повлиял на развитие других языков. «Такие вещи, как Linq, язык запросов в C#, на самом деле произошли от Haskell. Рабочие процессы F# и изменяемые состояния взяты непосредственно из его монадической структуры», — сказал главный исследователь Microsoft и ключевой контрибутор Haskell Саймон Пейтон Джонс.

Clojure — новый диалект LISP, созданный Ричем Хикки. Clojure отличается от других диалектов LISP тем, что он работает на платформе Java и компилируется в байт-код JVM, за счет чего программы на Clojure легко переносятся в любую среду с JVM. Язык также поддерживает ряд макросов, которые упрощают использование в нем существующих Java API. Структуры данных Clojure реализуют все стандартные интерфейсы Java, что делает легким запуск из Java программного кода, написанного на Clojure.

«Clojure обеспечивает легкий доступ к фреймворкам Java, с дополнительными подсказками и логикой типа, чтобы гарантировать, что вызовы Java могут избежать отражения», — объясняет Хикки. Он также говорит, что «подход Lisp к коду как данным и его макросистеме по-прежнему отличает его» от других диалектов Lisp и добавляет, что как и списки в Lisp, его карты, множества и векторы являются в Clojure первым классом. «Я думаю, что Clojure занимает уникальную нишу в качестве функционального Lisp для JVM с сильной поддержкой параллелизма», — добавил Хикки.

Elm — чисто функциональный язык, разработанный в 2012 г. Эваном Чаплицким. Он популярен среди веб-разработчиков, которым нравятся его возможности для создания пользовательских интерфейсов. Компилятор Elm предназначен для HTML, CSS и JavaScript. Он работает с библиотеками JavaScript почти так же, как Clojure — с библиотеками Java. Отличительной особенностью Elm является то, что он использует статическую проверку типов, которая помогает в устранении исключений во время выполнения, поскольку ошибки будут обнаружены на стадии компиляции. Отсутствие видимых ошибок на стороне пользователя — очевидное преимуществом этого языка.

Elixir — динамический функциональный язык, предназначенный для построения масштабируемых и обслуживаемых приложений. Он служит для создания систем с высокой доступностью и низкой задержкой. Elixir работает на базе экосистемы Erlang VM. Она востребована Heroku, WhatsApp, Klarna и другими проектами для распределенных, отказоустойчивых приложений. Каждый элемент приложений является выражением, функции языка Erlang могут быть вызваны без влияния на время исполнения из-за компиляции байт-кода в Erlang и наоборот.

F# — кроссплатформенный функциональный язык программирования с открытым кодом. Его разработку курирует F# Software Foundation. F# работает на Linux, Mac OS X, Android, iOS, Windows, графических процессорах и браузерах. Его можно применять свободно, он является языком с открытым исходным кодом и распространяется на условиях лицензии, одобренной OSI. F# затребован в широком спектре областей применения и активно поддерживается как со стороны сообщества Open Source, так и ведущими отраслевыми компаниями, предоставляющими профессиональные инструменты.

Idris — чисто функциональный язык программирования общего назначения, который включает особенности Haskell и метаязыка. Он характеризуется зависимыми типами, основанными на значениях, поэтому некоторые аспекты поведения программы могут быть точно определены в типе. Также реализована возможность компиляции в код на JavaScript (в том числе для Node.js) и компилирование по принципу «энергичных» вычислений (вычислять, не откладывая, все что возможно). Idris поддерживает два способа работы с системой автоматического доказательства: путем написания последовательных вызовов тактик (стиль Coq, при этом набор доступных тактик не столь богат, как в Coq, но может быть расширен штатными средствами метапрограммирования) или посредством пошаговой разработки доказательства (стиль Epigram и Agda).

JavaScript не является строго функциональным языком программирования, поскольку допускает объектно-ориентированный подход, однако у него есть компонент, который связывает его с ФП. Он включает в себя функции высшего порядка. Кроме того, новые версии стандарта ECMAScript предоставляют исправления для проблемы изменчивости.

Kotlin относится к числу новейших языков программирования. Он вышел в феврале 2016 г., но до этого в течении пяти лет проходил тестирование и активно дорабатывался. Его используют такие компании, как Amex, NBC Digital, Expedia и Gradle, но это не чисто функциональный язык. В этом отношении Kotlin можно сравнить с JavaScript, то есть с его помощью можно создавать как объектно-ориентированные, так и функциональные конструкции. Он обладает полной совместимостью с Java. К числу преимуществ Kotlin нужно отнести его лаконичность, в этом плане он более гибкий, чем Java.

Некоторые программисты считают, что он передает те же выражения, что и Java, но при этом ему требуется на треть меньше кода. Kotlin также предлагает все преимущества, связанные с функциональными языками программирования, включая функции высшего порядка, функции расширения и лямбда-выражения. Универсальность делает его подходящим для любого вида разработки, будь то серверные, клиентские веб-приложения или Android, и сейчас его создатели работают над совместимостью языка с iOS.

Scala — еще один гибридный язык, который можно применять как для объектно-ориентированного программирования, так и ФП. Статические типы Scala помогают избежать ошибок в сложных приложениях, а его среды выполнения JVM и JavaScript позволяют создавать высокопроизводительные системы с легким доступом к огромным экосистемам библиотек.

Главный специалист Telstra по аналитике больших данных Марк Молони считает, что программистам нужно обратить более пристальное внимание на функциональные языки программирования и заняться их изучением: «ФП окружает миф о его сложности или академичности, но я рассматриваю его как еще один источник информации для изучения. Чтобы освоить ФП, нужно время и практика, но этот путь ничем не отличается от того, который в конце 1980-х — начале 1990-х прошли разработчики для изучения объектно-ориентированного программирования. Технология продолжает развиваться. Это одна из причин, почему я люблю ПО. Важно уметь учиться, это равноценно тем знаниям, что у вас уже есть».

Версия для печати