Чиста функція

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

У програмування, чиста функція — це функція, яка має такі властивості:[1][2]

  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;
    }
    
  • бо повертане значення змінюється зі зміною нелокальної змінної
    int f() {
      return x;
    }
    
    З тої ж причини, наприклад, бібліотечна функція C++ 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() обчислене лише раз, перед циклом.

Примітки[ред. | ред. код]

  1. Bartosz Milewski (2013). Basics of Haskell. School of Haskell. FP Complete. Архів оригіналу за 27 жовтня 2016. Процитовано 13 липня 2018. Ось засадничі властивості чистих функцій: 1. Функція повертає той самий результат на кожен виклик з тим самим набором аргументів. Інакше кажучи, функція не має стану і не має доступу до зовнішнього стану. Кожного разу коли її викликають вона поводиться як новонароджене дитятко без спогадів і без знань про навколишній світ. 2. Функція не має побічних ефектів. Виклик функції один раз це те саме, що викликати її двічі і відкинути результат першого виклику.
  2. Brian Lonsdorf (2015). Professor Frisby's Mostly Adequate Guide to Functional Programming. GitHub. Процитовано 20 березня 2020. Чиста функція це функція, яка маючи той самий вхід, завжди повертає те саме значення і не має жодних спостережних побічних впливів.
  3. а б GCC 8.1 Manual. GCC, the GNU Compiler Collection. Free Software Foundation, Inc. 2018. Процитовано 28 червня 2018.