Язык LISP был разработан в 1958 году, как язык для работы с символьной структурированной информацией (а не числами как в FORTRAN). Чисто функциональное программирование хотя и было основным в языке, но также можно было использовать императивное (процедурное) программирование (включая goto). Также из ассемблера была заимствована идея макрокоманд. В середине 1980-гг в LISP было добавлено объектно-ориентированное расширение CLOS.
На LISP были разработаны первые экспертные системы (MYCIN, DENDRAL) и система символьных вычислений MACSYMA. До сих пор для разработки экспертных систем с явным заданием правил (в отличие от нейронных сетей) активно используется CLIPS с LISP-подобным синтаксисом (хотя сама программа написана на C).
При разработке Scheme в 1976 был сделан упор на простоту языка. Ядро языка содержит небольшое количество базовых функций, остальные функции и управляющие конструкции определяются через них. В 2007 появился ещё один наследник LISP - Clojure, имеющий развитую объектно-ориентированную составляющую и интеграцию с JVM.
Особенностью языков LISP-семейства кроме большого количества скобок, является динамическая типизация и, как следствие, относительно низкая скорость выполнения.
Альтернативный подход к функциональному программированию проявился в ветке языков семейства ML, в которых используется строгая типизация, основанная на системе вывода типов Хиндли-Милнера. Часть языков этого семейства (Standard ML, Haskell, Scala) поддерживает ленивый передачи аргументов (call-by-name), но большинство (OCaml, F#, Rust, Kotlin) - только энергичный, а для ленивых вычислений необходимы специальные классы. Языки с C-подобным синтаксисом (Rust, Scala, Kotlin) не требуют делать отступы в структурных операторах, а аргументы функции записываются в скобках через запятую, в остальных языках - отступы важны, а аргументы функции записываются через пробел без скобок, что приводит в сложных случаях к LISP-подобной программе:
Язык Kotlin в настоящее время является основным при разработке приложений для Android и, как все современные языки, является мультипарадигменным. При разработке языка основное внимание уделялось лаконичности и совместимости с Java. Также язык Kotlin входит в набор языков на соревнованиях ICPC, так как разработчик JetBrains является спонсором этих соревнований (остальные языки - это C++, Java, Python).
Можно проследить, что функциональные языки расширялись объектно-ориентированной парадигмой, и наоборот, традиционные языки - функциональной. Теперь можно не ограничиваться одним подходом при разработке, а выбирать наиболее подходящий для текущей решаемой задачи в рамках одного языка программирования.
Применение функционального подхода в C#, C++ и JavaScript на примере задачи "Вывести квадраты четных чисел в порядке возрастания из вектора v".
```cs
int[] v = { 5, 10, 8, 3, 6, 12}
// Функциональный подход с использованием лямбда-выражений
foreach (int i in (v.Where(n => n % 2 == 0).OrderBy(n => n).Select(n => n*n)))
{
Console.WriteLine("{1}",i);
}
// то же, через LINQ ("синтаксический сахар")
foreach (int i in (from n in v where n % 2 == 0 orderby n select n*n))
{
Console.WriteLine("{0}",i);
}
```
```cpp
std::vector<int> v{ 5, 10, 8, 3, 6, 12 };
// В C++14 появились только лямбда-выражения
std::vector<int> v2;
copy_if(v.begin(),v.end(),back_inserter(v2),[](auto n){ return n % 2 == 0; });
sort(v2.begin(),v2.end());
transform(v2.begin(),v2.end(),v2.begin(),[](auto n){ return n*n; });
for(auto i : v2)
{ std::cout<<i<<"\n";
}
// В C++20 ranges обеспечивают полноценный функциональный подход
namespace rs = std::ranges;
for (auto i : v | rs::views::filter([](auto n){ return n % 2 == 0; }) | rs::copy |
rs::actions::sort | rs::views::transform([](auto n){ return n*n; }))
{ std::cout<<i<<"\n";
}
```