Чиста функція
У програмування, чиста функція — це функція, яка має такі властивості:[1][2]
- повернені значення з функції тотожні для тотожних аргументів (ніяких змін разом з локальними статичними змінними, нелокальними змінними, мутовними аргументами-посиланями або потоками введення/виведення), і
- функція не має побічних впливів (не змінює локальні статичні змінні, нелокальні змінні, змінні аргументи-посилання або потоки введення/виведення).
Отже, чиста функція це обчислювальний аналог математичної функції. Деякі автори, особливо зі спільноти імперативних мов, використовують термін «чиста» для всіх функцій, що мають лише другу зі щойно наведених властивостей[3] (обговорено нижче).
Наступні приклади функцій з 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++ нечисті, бо вони не мають обох властивостей:
- бо повертане значення змінюється разом з локальною статичною змінною і через зміну локальної статичної змінної
int f() { static int x = 0; ++x; return x; }
- бо повертане значення змінюється залежно від стану потоку введення і сам потік введення зазнає змін
int f() { int x = 0; std::cin >> x; return x; }
Функції, що мають лише другу властивість дозволяють такі компіляторні техніки оптимізації як усунення спільних підвиразів і оптимізація циклів.[3] Приклад на 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()
обчислене лише раз, перед циклом.
- ↑ Bartosz Milewski (2013). Basics of Haskell. School of Haskell. FP Complete. Архів оригіналу за 27 жовтня 2016. Процитовано 13 липня 2018.
Ось засадничі властивості чистих функцій: 1. Функція повертає той самий результат на кожен виклик з тим самим набором аргументів. Інакше кажучи, функція не має стану і не має доступу до зовнішнього стану. Кожного разу коли її викликають вона поводиться як новонароджене дитятко без спогадів і без знань про навколишній світ. 2. Функція не має побічних ефектів. Виклик функції один раз це те саме, що викликати її двічі і відкинути результат першого виклику.
- ↑ Brian Lonsdorf (2015). Professor Frisby's Mostly Adequate Guide to Functional Programming. GitHub. Процитовано 20 березня 2020.
Чиста функція це функція, яка маючи той самий вхід, завжди повертає те саме значення і не має жодних спостережних побічних впливів.
- ↑ а б GCC 8.1 Manual. GCC, the GNU Compiler Collection. Free Software Foundation, Inc. 2018. Процитовано 28 червня 2018.