Referenčna preglednost je lastnost delov računalniških programov. Del programa imenujemo "referenčno pregleden", če ga lahko nadomestimo z vrednostjo, ki jo vrača, ne da bi spremenili obnašanje programa. Referenčno pregledna funkcija mora biti čista - vedno vrne enak izhod za enak vhod in ne sme imeti stranskih učinkov - delov programa, ki izvajajo drugo dejanje kot vračanje vrednosti. Nasprotje referenčne preglednosti je referenčna nepreglednost, kjer zamenjava izraza z njegovo vrednostjo lahko spremeni obnašanje programa.
Kaj to pomeni v praksi
V matematiki so vse funkcije referenčno pregledne, saj lahko matematična funkcija samo sprejme argument in vrne vrednost. Pri programiranju to ne velja vedno: funkcija lahko na primer preveri trenutni čas, bere ali piše datoteke, spreminja stanje programa ali na zaslon izpiše sporočilo. Zaradi tega se v programiranju za funkcije brez vrnitne vrednosti ali z efekti včasih uporabljajo drugačna imena, kot so postopki ali procedure.
Primeri čistih in nečistih funkcij
- Čista funkcija: funkcija, ki le izračuna vrednost iz vhodnih parametrov in nima stranskih učinkov. Primer v pseudo kodi:
Pri enakih x in y bo vedno vrnila isti rezultat in jo lahko varno nadomestimo z rezultatom.function add(x, y) { return x + y; } - Nečista funkcija: funkcija, ki poleg vrnitve vrednosti spreminja stanje ali je odvisna od zunanjega stanja:
Ti primeri niso referenčno pregledni, ker vrneta različne rezultate ali povzročita učinke ob vsakem klicu.function getCurrentTime() { return Date.now(); } function logAndReturn(x) { console.log(x); return x; }
Koristi referenčne preglednosti
Referenčna preglednost ponuja številne praktične prednosti za programerje in prevajalnike:
- Lažje dokazovanje pravilnosti programov: ker se izraze obravnava kot neodvisne enote, je lažje formalno preveriti, da program počne to, kar naj bi počel.
- Poenostavitev algoritmov in kode: delovne enote je mogoče zamenjati z njihovimi rezultati, s čimer se odpravi odvečno računanje.
- Lažje vzdrževanje in refaktoriranje: spremembe v enem delu kode manj verjetno vplivajo na drugje, če so funkcije čiste.
- Boljše možnosti optimizacije: prevajalniki in izvajalna okolja lahko varno izvajajo prepisovanje in druge optimizacije, ki pospešijo izvajanje ali zmanjšajo porabo pomnilnika.
- Enostavnejše testiranje: čiste funkcije so deterministične in jih je enostavno enotno testirati.
- Vzporedno izvajanje: ker čiste funkcije ne uporabljajo skupnega stanja, jih je varneje izvajati sočasno brez zapletov z zaklepi ali sinhronizacijo.
Optimizacije in tehnike, ki izkoriščajo referenčno preglednost
Obstaja več načinov, kako izkoristiti referenčno preglednost za izboljšanje učinkovitosti:
- Memoizacija (shranjevanje odgovorov po prvem poskusu): shranjevanje rezultatov klicev funkcije za kasnejšo ponovno uporabo brez ponovnega računanja.
- Odprava skupnih podizrazov: ugotavljanje in združevanje dveh enakih delov kode, da se izognemo podvajanju izračunov.
- Leno vrednotenje: izračun izraza šele, ko je njegova vrednost res potrebna, kar prihrani nepotrebno delo.
- Vzporejanje (delo na več problemih hkrati): varno porazdeljevanje dela med niti ali procesi, ker nečiste interakcije s skupnim stanjem niso prisotne.
Omejitve in opozorila
Čeprav je referenčna preglednost zaželena, ni vedno praktična ali mogoče popolnoma doseči v realnih aplikacijah. Nekateri deli programa morajo komunicirati z zunanjim svetom (vnos/izhod, omrežje, baza podatkov), kar prinese stranske učinke. V takih primerih se pogosto loči računanje (čiste funkcije) od efektov (IO), ali pa se uporabijo tehnike, ki efekte jasno izpisujejo in omejujejo njihov vpliv (npr. monade v funkcionalnih jezikih).
Zaključek
Referenčna preglednost poenostavi razmišljanje o kodi, omogoča močne optimizacije in prispeva k bolj zanesljivim ter lažje testirljivim programom. V praksi je cilj pogosto maksimirati dele aplikacije, ki so referenčno pregledni, in jasno ločiti tiste dele, ki morajo imeti stranske učinke.