Мое первое знакомство с функциональным программированием состоялось около трех лет назад, когда благодаря одному эссе Поля Грэма я заинтересовался языком Common Lisp. Проштудировав массу материала, доступного по этому языку, я впервые опробовал его на практике, написав курсовой по цифровой обработке сигналов. С тех пор функциональное программирование стало одной из наиболее интересных мне областей программирования, и элементы функционального стиля прочно вошли в тот код, который я пишу для работы и учебы.
Как известно, теоретические основы императивного программирования были заложены ещё в 1930-х годах Аланом Тьюрингом и Джоном фон Нейманом. Теория, положенная в основу функционального подхода, также родилась в 20-х — 30-х годах. В числе разработчиков математических основ функционального программирования можно назвать Моисея Шейнфинкеля и Хаскелла Карри, разработавших комбинаторную логику, и Алонзо Чёрча, создателя λ-исчисления.
Теория так и оставалась теорией, пока в конце 1950х годов Джон Маккарти и его студенты не разработали язык Lisp, который принято относить к функциональным языкам, хотя строго говоря он является мультипарадигменным языком, таким же как например Python. Lisp, разработанный Маккарти, дал начало целому семейству Lisp-подобных языков. На сегодняшний день существует два основных языка: это Scheme, используемый в основном в академической среде, и Common Lisp.
В конце 60-х годов интенсивно разрабатываются модели типизации, подходящие для функциональных языков. Большинство этих моделей включали в себя поддержку таких мощных механизмов как абстракция данных и полиморфизм. Параллельно Lisp-подобным языкам, которые изначально имели динамическую типизацию, появляется семейство языков ML с развитой полиморфной строгой системой типов. ML-языки легли в основу современных языков OCaml и Haskell.
Стоит отметить, что параллельно функциональным языкам развивались также императивные языки, которые благодаря своей семантической близости к машинным кодам компьютеров могли получить большую производительность на старых компьютерах. Именно этот факт, по моему мнению, послужил тому, что именно императивные языки стали мейнстримом и, пожалуй, остаются им по сей день, хотя и сдают понемного свои позиции в некоторых областях в пользу функциональных языков.
На данный момент существует целый зоопарк функциональных языков, в каждом из которых можно найти множество достоинств и недостатков. Я постарался свести наиболее значимые(по моему мнению) современные языки в табличку, представленную ниже. И т.к. статья под названием "Функциональное программирование" не будет являться таковой без примеров кода, то я добавил в таблицу колонку "Факториал", в которой дается канонический пример кода на каком-либо языке -- вычисление факториала. Итак, табличка:
Язык | Краткая характеристика | Факториал |
---|---|---|
Common Lisp | Мультипарадигменный: Функциональный, процедурный, объектно-ориентированный, метапрограммирование; динамическая типизация |
(defun factorial (n) (if (<= n 1) 1 (* n (factorial (- n 1))))) |
Python | Мультипарадигменный: Функциональный, процедурный, объектно-ориентированный; динамическая duck типизация |
def factorial(n): return reduce(lambda x, y: x*y, range(1, n+1)) |
Erlang | Мультипарадигменный: Конкурентный, Функциональный; динамическая типизация |
fac(0) -> 1; fac(N) when N > 0, is_integer(N) -> N * fac(N-1). |
OCaml | Мультипарадигменный: императивный, функциональный, объектно-ориентированный; статическая строгая типизация |
let rec fact n = if n =/ Int 0 then Int 1 else n */ fact(n -/ Int 1);; val fact : Num.num -> Num.num = ⟨fun⟩ |
F# | Мультипарадигменный: императивный, функциональный, объектно-ориентированный; статическая строгая типизация |
let rec factorial n = match n with | 0 -> 1 | _ -> n * factorial (n - 1) |
Haskell | Чисто функциональный, lazy, строгая статическая типизация |
factorial :: Integer -> Integer factorial n = product [1..n] |
На сегодняшний день, функциональные языки и элементы функционального программированию все больше входят в мейнстрим и наблюдается явный тренд в сторону укрепления позиций ФП. Ранее такому сдвигу препятствовал фактор производительности -- зачастую приходилось выбирать более низкоуровневые и производительные языки программирования типа С++. Однако сейчас, когда существуют с одной стороны довольно продвинутые компиляторы функциональных языков и быстрые многоядерные компьютеры, фактор производительности отходит на задний план. В этом можно убедиться, посмотрев на тесты в Computer Languages Shootout. Можно заметить более высокую или сравнимую производительность ФЯ по сравнению с императивными языками на многих тестах.
Существует также множество других моментов, препятствующих всеобщему использованию ФП, однако ясно одно -- в ближайшем будущем функциональные языки займут сильные позиции во многих сферах программирования и прочно войдут в мейнстрим программирования, что явно можно наблюдать уже сегодня.