Tiszta függvény

A Wikipédiából, a szabad enciklopédiából

A számítógépes programozásban a tiszta függvény egy olyan függvény, amely a következő tulajdonságokkal rendelkezik:[1][2]

  1. Visszatérési értéke ugyanaz, ugyanazon argumentum esetén (nincs változás a helyi Statikus változókkal, nem lokális változókkal, mutálható referencia argumentumokkal vagy bemeneti folyamokkal az I/O eszközökből).
  2. Az értékelésnek nincs mellékhatása (a helyi statikus változók, nem lokális változók, mutálható referencia-argumentumok vagy I/O-folyamok nem mutálódnak).

Így egy tiszta függvény egy matematikai függvény számítási analógja. Egyes szerzők, különösen az imperatív nyelvi közösség, a "tiszta" kifejezést használják minden olyan függvényre, amely csak a fenti tulajdonságokkal rendelkezik.[3][4]

Példák[szerkesztés]

Tiszta függvények[szerkesztés]

A C++ függvények következő példái tiszták:

  • floor, egy szám egészrészét adja vissza;
  • max, két érték közül a nagyobbik értékét adja vissza;
  • sin, egy szám szinuszával tér vissza.

Tisztátlan függvények[szerkesztés]

A következő C++ függvények nem tiszták, mivel nem felelnek meg a fenti 1. pontnak:

  • a nem lokális változó visszatérési értékváltozása miatt
int f() {
  return x;
}
  • a visszatérő érték változása miatt, amely mutálható referencia argumentummal rendelkezik
int f(int* x) {
  return *x;
}

A következő C++ függvények nem tiszták, mivel nem felelnek meg a fenti 2. pontnak:

  • a helyi statikus változó mutációja miatt
void f() {
  static int x = 0;
  ++x;
}
  • nem lokális változó mutációja miatt
void f() {
  ++x;
}
  • egy mutálható referencia argumentum mutációja miatt
void f(int* x) {
  ++*x;
}
  • egy kimeneti áramlat mutációja miatt
void f() {
  std::cout << "Hello, world!" << std::endl;
}

A következő C++ függvények nem tiszták, mivel hiányoznak mind a fenti 1, mind a 2 tulajdonságok:

  • a visszatérő értékváltozás miatt a helyi statikus változóval és a helyi statikus változó mutációjával
int f() {
  static int x = 0;
  ++x;
  return x;
}
  • a visszatérési érték változása miatt egy bemeneti árammal és egy bemeneti áram mutációjával
int f() {
  int x = 0;
  std::cin >> x;
  return x;
}

I/O tiszta funkciókban[szerkesztés]

Az I/O eredetileg tisztázatlan: a bemeneti műveletek aláássák a referencia-átláthatóságot, és a kimeneti műveletek mellékhatásokat hoznak létre. Mindazonáltal van értelme, hogy a függvény képes legyen bemeneti vagy kimeneti feladatok elvégzésére, és még mindig tiszta legyen, ha a vonatkozó I/O-eszközök működésének sorrendje kifejezetten mint argumentum és eredmény, és az I/O műveletekre nem sikerül, ha a bemeneti sorrend nem írja le a program végrehajtása óta ténylegesen végrehajtott műveleteket.

A második pont biztosítja, hogy az egyetlen argumentumként használható szekvencia minden I/O műveletnél megváltozzon; az első lehetővé teszi az I/O-teljesítő funkcióhoz tartozó különböző hívások különböző eredményeinek visszaadását a megváltozott szekvencia argumentumok miatt.[5][6]

Az I/O monád egy olyan programozási idióma, amelyet tipikusan az I/O végrehajtására használnak tiszta funkcionális nyelveken.

Fordító optimalizálások[szerkesztés]

Azok a funkciók, amelyek csak a fenti 2. pontnak felelnek meg, lehetővé tesznek fordítóoptimalizálási technikákat, mint például az aritmetikai operátorokhoz hasonló közös alexpressziós eltávolítás és hurok optimalizálás.[3] Egy C++ példa a length metódus, amely a karakterlánc nagyságát adja vissza, amely memória tartalmától függ amelyre a karakterláncra mutat, ezért nem felel meg a fenti 1. pontnak. Mindazonáltal egyszálú környezetben az alábbi C++ kód

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];
}

optimalizálható úgy, hogy az s.length() értékét csak egyszer, a hurok előtt számoljuk ki.

Fortran-ban a pure kulcsszó használható arra, hogy egy függvényt csak mellékhatássá nyilvánítson (azaz csak a fenti tulajdonság 2). A C ++ -ban a constexpr kulcsszó használható arra, hogy egy függvényt a fenti 1-es és 2-es tulajdonságokkal constexpr (azaz tisztán legyen ebben a cikkben használt értelemben); az ilyen funkciók a többszálas környezetben is közös alexpressziós eltávolítási és hurok optimalizálásnak vannak kitéve.

Lásd még[szerkesztés]

  1. Bartosz Milewski: Basics of Haskell. School of Haskell. FP Complete, 2013 [2016. október 27-i dátummal az eredetiből archiválva]. (Hozzáférés: 2018. július 13.) „Here are the fundamental properties of a pure function: 1. A function returns exactly the same result every time it's called with the same set of arguments. In other words a function has no state, nor can it access any external state. Every time you call it, it behaves like a newborn baby with blank memory and no knowledge of the external world. 2. A function has no side effects. Calling a function once is the same as calling it twice and discarding the result of the first call.”
  2. Brian Lonsdorf: Professor Frisby's Mostly Adequate Guide to Functional Programming. GitBook, 2015 [2019. július 6-i dátummal az eredetiből archiválva]. (Hozzáférés: 2018. július 14.) „A pure function is a function that, given the same input, will always return the same output and does not have any observable side effect.”
  3. a b GCC 8.1 Manual. GCC, the GNU Compiler Collection. Free Software Foundation, Inc., 2018 (Hozzáférés: 2018. június 28.)
  4. Fortran 95 language features#Pure Procedures
  5. Peyton Jones, Simon L.. Haskell 98 Language and Libraries: The Revised Report [archivált változat]. Cambridge, United Kingdom: Cambridge University Press, 95. o. (2003. április 26.). ISBN 0-521 826144. Hozzáférés ideje: 2014. július 17. [archiválás ideje: 2021. május 6.] 
  6. Hanus: Curry: An Integrated Functional Logic Language. http://www-ps.informatik.uni-kiel.de/currywiki/. Institut für Informatik, Christian-Albrechts-Universität zu Kiel. [2014. július 25-i dátummal az eredetiből archiválva]. (Hozzáférés: 2014. július 17.)

További információk[szerkesztés]