Чистая функция
Эта статья написана как руководство или руководство . ( май 2024 г. ) |
В компьютерном программировании — чистая функция это функция , обладающая следующими свойствами: [1] [2]
- функции возвращаемые значения идентичны аргументов для идентичных ( никаких изменений с локальными статическими переменными , нелокальными переменными , изменяемыми ссылочными аргументами или входными потоками , т. е. ссылочная прозрачность ), и
- функция не имеет побочных эффектов (нет мутаций локальных статических переменных, нелокальных переменных, изменяемых ссылочных аргументов или потоков ввода/вывода).
Примеры [ править ]
Чистые функции [ править ]
Следующие примеры функций C++ являются чистыми:
floor
, возвращая пол числа;max
, возвращая максимум два значения.- функция f , определяемая как
Стоимость
void f() { static std::atomic<unsigned int> x = 0; ++x; }
x
можно наблюдать только внутри других вызововf()
, и какf()
не сообщает о ценностиx
для окружающей среды он неотличим от функцииvoid f() {}
это ничего не дает. Обратите внимание, чтоx
являетсяstd::atomic
так что изменения из нескольких потоков, выполняющихсяf()
одновременно не приводят к гонке данных , которая имеет неопределенное поведение в C и C++.
Нечистые функции [ править ]
Следующие функции C++ являются нечистыми, поскольку им не хватает указанного выше свойства 1:
- из-за изменения возвращаемого значения со статической переменной
int f() { static int x = 0; ++x; return x; }
- из-за изменения возвращаемого значения с нелокальной переменной
По той же причине, например, библиотечная функция C++
int f() { return x; }
sin()
не является чистым, поскольку его результат зависит от режима округления IEEE , который можно изменить во время выполнения. - из-за изменения возвращаемого значения с изменяемым ссылочным аргументом
int f(int* x) { return *x; }
- из-за изменения возвращаемого значения в зависимости от входного потока
int f() { int x = 0; std::cin >> x; return x; }
Следующие функции C++ являются нечистыми, поскольку им не хватает указанного выше свойства 2:
- из-за мутации локальной статической переменной
void f() { static int x = 0; ++x; }
- из-за мутации нелокальной переменной
void f() { ++x; }
- из-за мутации изменяемого ссылочного аргумента
void f(int* x) { ++*x; }
- из-за мутации выходного потока
void f() { std::cout << "Hello, world!" << std::endl; }
Следующие функции C++ являются нечистыми, поскольку в них отсутствуют свойства 1 и 2:
- из-за изменения возвращаемого значения с помощью локальной статической переменной и мутации локальной статической переменной
int f() { static int x = 0; ++x; return x; }
- из-за изменения возвращаемого значения в зависимости от входного потока и мутации входного потока
int f() { int x = 0; std::cin >> x; return x; }
Ввод-вывод в чистых функциях [ править ]
Ввод-вывод по своей сути нечист: операции ввода подрывают ссылочную прозрачность , а операции вывода создают побочные эффекты. Тем не менее, в некотором смысле функция может выполнять ввод или вывод и при этом оставаться чистой, если последовательность операций на соответствующих устройствах ввода-вывода моделируется явно как аргумент и результат, а операции ввода-вывода принимаются потерпеть неудачу, когда входная последовательность не описывает операции, фактически выполненные с момента начала выполнения программы. [ нужны разъяснения ]
Второй момент гарантирует, что единственная последовательность, которую можно использовать в качестве аргумента, должна меняться при каждом действии ввода-вывода; первый позволяет различным вызовам функции ввода-вывода возвращать разные результаты из-за изменения аргументов последовательности. [3] [4]
Монада ввода-вывода — это идиома программирования, обычно используемая для выполнения ввода-вывода на чисто функциональных языках.
Мемоизация [ править ]
Выходные данные чистой функции могут быть предварительно вычислены и кэшированы в справочной таблице. В методе, называемом мемоизацией , любой результат, возвращаемый данной функцией, кэшируется, и при следующем вызове функции с теми же входными параметрами кэшированный результат возвращается вместо повторного вычисления функции.
Мемоизацию можно выполнить, обернув функцию в другую функцию ( функцию-обертку ). [5]
С помощью мемоизации вычислительные усилия, необходимые для вычислений самой функции, могут быть уменьшены за счет накладных расходов на управление кэшем и увеличения требований к памяти.
Программа C для кэшированного вычисления факториала ( assert()
прерывается с сообщением об ошибке, если его аргумент ложный; на 32-битной машине значения выходят за рамки fact(12)
все равно не может быть представлено. [ нужна ссылка ]
static int fact(int n) {
return n<=1 ? 1 : fact(n-1)*n;
}
int fact_wrapper(int n) {
static int cache[13];
assert(0<=n && n<13);
if (cache[n] == 0)
cache[n] = fact(n);
return cache[n];
}
Оптимизация компилятора [ править ]
Функции, которые обладают только указанным выше свойством 2, то есть не имеют побочных эффектов, допускают методы оптимизации компилятора, такие как исключение общих подвыражений и оптимизация цикла , аналогичная арифметическим операторам. [6] Примером C++ является length
метод, возвращающий размер строки, который зависит от содержимого памяти, на которое указывает строка, поэтому отсутствует указанное выше свойство 1. Тем не менее, в однопоточной среде следующий код C++
std::string s = "Hello, world!";
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int l = 0;
for (int i = 0; i < 10; ++i) {
l += s.length() + a[i];
}
можно оптимизировать так, чтобы значение s.length()
вычисляется только один раз, перед циклом.
Некоторые языки программирования позволяют объявлять чистое свойство функции:
- В Фортране и D
pure
Ключевое слово можно использовать для объявления функции свободной от побочных эффектов (т.е. имеющей только указанное выше свойство 2). [7] Компилятор может вывести свойство 1 поверх объявления. [8] См. также: Особенности языка Fortran 95 § Чистые процедуры . - В Персидского залива странах
pure
Атрибут указывает свойство 2, а атрибутconst
Атрибут определяет действительно чистую функцию с обоими свойствами. [9] - Языки, предлагающие выполнение функций во время компиляции, могут требовать, чтобы функции были чистыми, иногда с добавлением некоторых других ограничений. Примеры включают в себя
constexpr
C++ (оба свойства). [10] См. также: C++11 § constexpr — Обобщенные константные выражения .
Модульное тестирование [ править ]
Поскольку чистые функции имеют одинаковые возвращаемые значения для одинаковых аргументов , они хорошо подходят для модульного тестирования .
См. также [ править ]
- Выполнение функции во время компиляции . Оценка чистых функций во время компиляции.
- Детерминированный алгоритм - алгоритм, который при определенных входных данных всегда будет выдавать один и тот же результат.
- Идемпотентность - свойство операций, благодаря которому их можно применять несколько раз без изменения результата.
- Лямбда-исчисление - Математико-логическая система, основанная на функциях.
- Чисто функциональная структура данных . Структура данных, реализуемая на чисто функциональных языках.
- Реентерабельность (вычисления) – одновременное выполнение функции без вмешательства в другие вызовы.
Ссылки [ править ]
- ^ Бартош Милевский (2013). «Основы Хаскеля» . Школа Хаскеля . ФП завершено. Архивировано из оригинала 27 октября 2016 г. Проверено 13 июля 2018 г.
- ^ Брайан Лонсдорф (2015). «В основном адекватное руководство профессора Фрисби по функциональному программированию» . Гитхаб . Проверено 20 марта 2020 г.
- ^ Пейтон Джонс, Саймон Л. (2003). Язык Haskell 98 и библиотеки: пересмотренный отчет (PDF) . Кембридж, Соединенное Королевство: Издательство Кембриджского университета. п. 95. ИСБН 0-521 826144 . Проверено 17 июля 2014 г.
- ^ Ханус, Майкл. «Карри: интегрированный язык функциональной логики» (PDF) . www-ps.informatik.uni-kiel.de . Институт компьютерных наук Университета Кристиана Альбрехта в Киле. п. 33. Архивировано из оригинала (PDF) 25 июля 2014 года . Проверено 17 июля 2014 г.
- ^ Алей, Р. (2017). Профессиональное функциональное программирование на PHP: стратегии разработки приложений для оптимизации производительности, параллелизма, тестируемости и краткости кода . SpringerLink: Бюхер. Апресс. п. 109. ИСБН 978-1-4842-2958-3 . Проверено 4 февраля 2024 г.
- ^ «Атрибуты общих функций — использование коллекции компиляторов GNU (GCC)» . gcc.gnu.org, Коллекция компиляторов GNU . Фонд свободного программного обеспечения, Inc. Проверено 28 июня 2018 г.
- ^ Чистый атрибут в Фортране
- ^ Чистый атрибут на языке D
- ^ «Атрибуты общих функций» . Использование коллекции компиляторов GNU (GCC . Дата обращения 22 июля 2021 г. ).
- ^ атрибут constexpr в C++