Pure functions (čisté funkce) jsou základním stavebním kamenem funkcionálního programování. Tyto funkce poskytují konzistentní výsledek (jsou deterministické) a nemají žádné vedlejší efekty.
Hlavní výhody pure funtion
Jejich výhoda spočívá v tom, že se snadno testují, lépe se refaktorují a při znovupoužití těchto funkcí se nemusíme tolik obávat neočekávaného chování a to vede k jednoduššímu a efektivnějšímu programování. Tyto funkce mohou být také snadno paralelizovány a optimalizovány, protože nezávisí na jiném vnějším stavu programu. Pure funkce jsou tedy vždy referenčně transparentní.
Referenční transparentnost
Matematická funkce, nebo zobrazení je v programování často používán jako model čistých funkcí, protože mají stejné vlastnosti a jsou dobře definovány. Tedy pokud funkce dostane stejný vstupní argument, bude vždy stejnou hodnoru bez ohledu na to, kdy, kde nebo jak se funkce používá.
Mohli bychom volání takové funkce klidně nahradit tabulkou (memoizovat) nebo vyhodnoceným výrazem výsledkem, aniž by se změnilo chování programu. To umožňuje efektivní použití memoizace a jiných technik pro optimalizaci výkonu.
Vedlejší efekty
Čistá funkce by neměla mít žádný vedlejší efekt, což znamená, že nezmění stav svého okolí. To znamená, že například
- nijak neovlivňuje globální proměnné a objekty,
- nemají vliv na jakoukoli části kódu, která není uvnitř dané čisté funkce,
- neovlivňují vnější zdroje, neprovádí i/o operace či zásahy do filesystemu Také uvnitř nevolají jiné než čisté funkcí uvnitř funkce.
Taková funkce tedy nepřispívá k nečekanému chování aplikace, pokud je volána vícekrát se stejnými argumenty.
Příklad
Příklad čisté funkce v JavaScriptu:
function add(a, b) {
return a + b;
}
Ne všechny funkce mohou být čisté, ale však jsou je to často dobrá volba. Například funkce v Reactu a Redux reducery musí být čisté, aby bylo zajištěno správné vykreslování prvků uživatelského rozhraní.
Co jsou nečisté funkce
Nečistá funkce je jednoduše funkce, která není čistá, tedy není referenčně transparentní,. Tyto funkce tedy pak nemají logicky vlastnosti čistých funkcí a mohou být obtížné na testování, a problematické při ladění a údržbě kódu.
Generování náhodného čísla
Jako impure funkci, si můžeme představit funkci, která generuje náhodná čísla, protože jejich výstup závisí na něčem dalším než pouze na jejich argumentech.
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
Podobným příkladem je i datum
const start = Date.now();
Protože po každém zavolání dostaneme jinou hodnotu.
Modifikace globální proměnné
Zde je příklad side efektu funkce, která změní globální proměnnou:
let celkem = 0;
function pridatJeden() {
celkem++;
}
Navíc operátor inkrementace také způsobuje vedlejší efekt, protože dělá obvykle dvě věci naráz - přičítá jedničku a navrací nějakou hodnotu. Nečistá funkce by byla i taková která by jen četla hodnotu globální proměnné.
Modifikace objektu
V JS jsou objekty předávány referencí (ne hodnotou), a tedy modifikace objektu cart
v této funkci ovlivní tento objekt, který jsme předali jako argument.
Tento druh side effectu může být problematický, pokud očekáváme, že původní objekt zůstane beze změn.
function addToCart(item, cart) {
cart.items.push(item);
return cart;
}
Funkce modifikuje pole items
v objektu cart
, aby přidala novou položku do košíku.
Můžeme se snažit zabránit tomuto side effectu tím, že budeme vytvářet kopie objektů, namísto toho, abychom pracovali s originály, nebo že budeme předávat pouze potřebné hodnoty, namísto celých objektů.
Výpis na konsoli
Pokud funkce volá jinou funkci, která má vedlejší efekt. Například:
function loging() {
console.log("Hello");
}
Asynchronní operace
Pokud funkce provádí asynchronní operace, jako například volá API nebo načítá data ze souboru z filesystemu.
function fetchData(url) {
fetch(url)
.then(response => response.json())
.then(data => console.log(data));
}
V JS lze dosáhnout čisté funkce, která komunikuje s API nebo souborovým systémem, pomocí asynchronního přístupu a použitím Promise nebo async/await syntaxe. Funkce může vrátit Promise, který pak může být zpracován jinou čistou funkcí nebo další asynchronní funkcí pomocí metody .then() nebo await.