Чистота языка программирования
Чистота́ (в отношении языка программирования) — отсутствие побочных эффектов. Язык программирования является чистым в том случае, если все функции в программах этого языка являются чистыми.
Программы, написанные на чистых языках программирования, проще отлаживать, верифицировать, в них проще обнаруживать ошибки, которые не удалось обнаружить с помощью тестирования. Программы на чистом языке программирования проще переписывать, избегая внесения ошибок. В то же время, сам процесс планирования программы с расчётом на чистоту сложнее.
Ещё одним важным преимуществом чистых функциональных языков является параллелизм. Поскольку все функции для вычислений используют только свои параметры, можно организовать вычисление независимых функций в произвольном порядке или параллельно, на результат вычислений это не повлияет. Параллелизм может быть организован не только на уровне компилятора языка, но и на уровне архитектуры технических средств. Существуют экспериментальные компьютеры, основанные на подобных архитектурах, например Lisp-машина.
Чистые функциональные языки временами называют «детерминированными» в том смысле, что для всякой функции каждый вызов всегда даёт один и тот же эффект (в императивных языках это, вообще говоря, не верно). В то же время, такие языки называют «недетерминированными» в том смысле, что порядок действительного исполнения программы может сильно меняться в зависимости от конкретной реализации языка: алгоритмы могут неявно распараллеливаться, промежуточные данные могут исключаться из цепочки преобразований, представление одних и тех же типов может варьироваться даже в рамках одной программы, и т. д. (для императивных языков это попросту невозможно). Проще говоря, чистые языки детерминированы на уровне исходных кодов и недетерминированы на уровне реализации (императивные — наоборот).
Ввод-вывод и чистота
Наиболее серьёзной областью применения языков программирования, в которой постоянно присутствуют побочные эффекты в функциях, является ввод-вывод. Можно полагать, что любая операция ввода данных от пользователя является действием с побочным эффектом, т. к. нельзя заранее сказать, что именно введёт пользователь в качестве значений параметров, использующихся в вычислительном процессе. Хотя некоторые исследователи и учёные-теоретики утверждают, что ввод-вывод нельзя рассматривать в качестве примера наличия побочных эффектов, т. к. по сути ввод-вывод — это изменение окружения программы, но в любом случае ввод-вывод делает использующие его функции недетерминированными.
В чистом функциональном программировании оператор присваивания отсутствует, объекты нельзя изменять и уничтожать, можно только создавать новые путём декомпозиции и синтеза существующих. О ненужных объектах позаботится встроенный в любой транслятор функционального языка сборщик мусора. Благодаря этому в чистых функциональных языках все функции свободны от побочных эффектов. Однако это не мешает этим языкам имитировать некоторые полезные императивные свойства, такие, как обработка исключений и изменяемые (деструктивно) массивы. Для этого существуют специальные методы.
Однако некоторые причины наличия функций с побочными эффектами полностью убрать из функциональных языков программирования нельзя, т. к. в таком случае такие языки были бы слишком ограничены в практическом применении. В первую очередь это относится именно к вводу-выводу. Сложно представить себе полноценный язык программирования, где нет возможности осуществлять ввод данных от пользователя в интерактивном режиме, а также осуществлять вывод данных для пользователя.
Монады
Для обеспечения возможности использования таких технологий, как ввод-вывод, без умаления свойства чистоты, во многих функциональных языках программирования, в том числе и в языке Haskell, используется специальный механизм, названный «монадой». Монады как бы обёртывают необходимые императивные свойства, не допуская их смешивания с чистым синтаксисом функционального языка. Использование монад позволило реализовать все те узкие места, которые регламентировали наличие побочных эффектов в функциях.
Так, например, для обеспечения ввода-вывода в языке Haskell реализована стандартная монада IO
, вне которой невозможно выполнить ни одной операции ввода-вывода. Такими же свойствами обладают и все остальные стандартные монады, реализованные для языка Haskell.