В информатике чисто функциональное программирование обычно обозначает парадигму программирования — стиль построения структуры и элементов компьютерных программ, — которая рассматривает все вычисления как оценку математических функций .
Состояние программы и изменяемые объекты обычно моделируются с помощью временной логики , как явные переменные, которые представляют состояние программы на каждом этапе выполнения программы: переменное состояние передается как входной параметр функции преобразования состояния, которая возвращает обновленное состояние как часть своего возвращаемого значения. Этот стиль обрабатывает изменения состояния, не теряя ссылочной прозрачности выражений программы.
Чисто функциональное программирование заключается в обеспечении того, что функции внутри функциональной парадигмы будут зависеть только от своих аргументов, независимо от любого глобального или локального состояния. Чисто функциональная подпрограмма имеет видимость только изменений состояния, представленных переменными состояния, включенными в ее область действия.
Точное различие между чистым и нечистым функциональным программированием является предметом споров. Предложенное Сабри определение чистоты заключается в том, что все общие стратегии оценки (вызов по имени, вызов по значению и вызов по необходимости) дают одинаковый результат, игнорируя стратегии, которые ошибочны или расходятся. [1]
Программа обычно считается функциональной, когда она использует некоторые концепции функционального программирования , такие как функции первого класса и функции высшего порядка . [2] Однако функция первого класса не обязательно должна быть чисто функциональной, поскольку она может использовать методы из императивной парадигмы, такие как массивы или методы ввода/вывода , которые используют изменяемые ячейки, которые обновляют свое состояние в качестве побочных эффектов. Фактически, самые ранние языки программирования, упомянутые как функциональные, IPL и Lisp , [3] [4] оба являются «нечистыми» функциональными языками по определению Сабри.
Каждая стратегия оценки , которая заканчивается на чисто функциональной программе, возвращает тот же результат. В частности, это гарантирует, что программисту не придется думать, в каком порядке оцениваются программы, поскольку жадная оценка вернет тот же результат, что и ленивая оценка . Однако все еще возможно, что жадная оценка может не завершиться, пока ленивая оценка той же программы останавливается. Преимущество этого в том, что ленивая оценка может быть реализована намного проще; поскольку все выражения будут возвращать тот же результат в любой момент (независимо от состояния программы), их оценка может быть отложена настолько, насколько это необходимо.
В чисто функциональном языке единственными зависимостями между вычислениями являются зависимости данных, а вычисления детерминированы. Поэтому для параллельного программирования программисту нужно только указать части, которые должны быть вычислены параллельно, а среда выполнения может обрабатывать все остальные детали, такие как распределение задач по процессорам, управление синхронизацией и коммуникацией, а также сбор мусора параллельно. Этот стиль программирования позволяет избежать распространенных проблем, таких как состояния гонки и взаимоблокировки, но имеет меньший контроль, чем императивный язык. [5]
Чтобы обеспечить ускорение, гранулярность задач должна быть тщательно выбрана, чтобы не быть ни слишком большой, ни слишком маленькой. Теоретически, можно использовать профилирование времени выполнения и анализ времени компиляции, чтобы оценить, ускорит ли введение параллелизма программу, и, таким образом, автоматически распараллелить чисто функциональные программы. На практике это не было особенно успешным, и полностью автоматическое распараллеливание непрактично. [5]
Чисто функциональные структуры данных являются постоянными . Для функционального программирования требуется сохранение; без него одно и то же вычисление может возвращать разные результаты. Функциональное программирование может использовать постоянные нечисто функциональные структуры данных , в то время как эти структуры данных не могут использоваться в чисто функциональных программах.
Чисто функциональные структуры данных часто представляются иначе, чем их императивные аналоги. [6] Например, массив с постоянным временем доступа и обновления является базовым компонентом большинства императивных языков, и многие императивные структуры данных, такие как хэш-таблица и двоичная куча , основаны на массивах. Массивы можно заменить картой или списком случайного доступа, которые допускают чисто функциональную реализацию, но время доступа и обновления логарифмическое . Поэтому чисто функциональные структуры данных могут использоваться в языках, которые не являются функциональными, но они могут быть не самым эффективным доступным инструментом, особенно если не требуется персистентность.
В общем случае преобразование императивной программы в чисто функциональную также требует обеспечения того, чтобы ранее изменяемые структуры теперь явно возвращались из функций, которые их обновляют, — такая структура программы называется стилем передачи хранилища .
Чисто функциональный язык — это язык, допускающий только чисто функциональное программирование. Однако чисто функциональные программы могут быть написаны на языках, которые не являются чисто функциональными.