A funkcionális programozás egy deklaratív programozási paradigma típus, amely a számítást matematikai függvények értékelésének tekinti.
Mivel az állapotváltozás és az adatok mutációja nem ábrázolható függvényértékelésekkel, a funkcionális programozás ezeket nem ismeri el, éppen ellenkezőleg, a funkciók alkalmazását hangsúlyozza, ellentétben az imperatív programozási modellel, amely az állapotváltozások előtt hangsúlyozza.
A funkcionális nyelv tehát egy programozási nyelv, amelynek szintaxisa és jellemzői ösztönzik a funkcionális programozást. Míg a funkcionális programozás eredete a lambda-calculusban található , a legrégebbi funkcionális nyelv a Lisp , amelyet 1958- ban McCarthy hozott létre . Lisp olyan változatokat adott életre, mint a Scheme ( 1975 ) és a Common Lisp ( 1984 ), amelyek Lisp-hez hasonlóan nem vagy csak kissé vannak gépelve . Az olyan funkcionális nyelvek, mint az ML ( 1973 ), Haskell ( 1987 ), OCaml , Erlang , Clean és Oz , CDuce , Scala ( 2003 ), F # vagy PureScript ( 2013 ), Agda (en) , erősen be vannak írva.
A funkcionális programozás radikálisan megszabadul a mellékhatásoktól (vagy mellékhatásoktól) azáltal, hogy megtiltja a hozzárendelési műveleteket.
A funkcionális paradigma nem használ állami gép leírására program, hanem egy összekapcsolódó funkciók, hogy működnek a „fekete doboz”, amely lehet az egymásba ágyazott. Minden olyan mezőben, amelynek több paramétere van a bemenetben, de csak egy kimenete van, csak egy lehetséges értéket adhat ki a bemenetben bemutatott értékek mindegyikéhez. Így a funkciók nem vezetnek be mellékhatásokat. A program tehát matematikai értelemben olyan alkalmazás , amely minden bemeneti értékkészlethez csak egy eredményt ad. Ez a gondolkodásmód, amely nagyon eltér az imperatív programozási megközelítéstől, az egyik fő oka annak a nehézségnek, amelyet az imperatív nyelveken kiképzett programozóknak okoz a funkcionális programozás megközelítése. Azonban általában nem jelent különösebb nehézséget azoknak a kezdőknek, akik soha nem voltak kitéve az imperatív nyelveknek. A mellékhatások nélküli funkciók fontos előnye az a könnyűség, hogy egyedileg kell tesztelnünk őket. Ezenkívül az automatikus memóriakezelés széleskörű használata szemétgyűjtővel egyszerűsíti a programozó feladatát.
A gyakorlatban, a hatékonyság érdekében, valamint azért, mert egyes algoritmusok könnyen kifejezhető egy olyan gép, valamilyen funkcionális nyelvek lehetővé imperatív programozási azáltal, hogy meghatározza, hogy bizonyos változók hozzárendelhető (vagy változékony szerint a szokásos neve), és így a lehetőséget a lokálisan bevezetett élhatásokról . Ezeket a nyelveket nem tiszta funkcionális nyelvek alatt csoportosítják .
Az úgynevezett tisztán funkcionális nyelvek nem teszik lehetővé az imperatív programozást. Valójában nincsenek mellékhatásaik és védve vannak az egyidejű végrehajtás problémáival szemben . Láthatjuk például, hogy mi történt az erlang nyelv keretein belül .
A funkcionális nyelvek megvalósítása kifinomultan használja a verem, mert az ideiglenes adatok tömbökben történő tárolásának szükségességének leküzdése érdekében nagyban támaszkodnak a rekurzióra (beleértve a függvény hívását a saját definíciójában). Egy műszaki többszörösei, hogy a válogatás a leghatékonyabb rekurzió nevezett technikával farok rekurzió (in English : tail-rekurzió ), amely abból áll, hogy összegyűjti a részeredményeket a memória cella a köteg és adja át paraméterként a rekurzív hívás . Ez lehetővé teszi a rekurzív hívások halmozásba kerülését azáltal, hogy egyszerű ugrásokkal helyettesíti őket. A fordító által generált kód ekkor hasonló az imperatív hurok által generált kódhoz. Néhány nyelv, például a Scheme , az OCaml és az Anubis, automatikusan optimalizálja a rekurzív hívásokat.
Imperatív programozási alapul modell az állami gépek (lásd még Turing-gép és Neumann-architektúra ), a központi memória és utasításokat, amelyek módosítják az állami egymást követő feladatok. Egy ilyen programot egy állapotgép képvisel (lásd a számláló gépet ), amely a memória egymást követő állapotait képviseli. Ehhez a programozónak mindenkor rendelkeznie kell a program által módosított memória állapotának pontos modelljével.
A feladat bonyolultságának csökkentése érdekében számos technika csökkenti az egyszerre kezelendő változók számát, többségük strukturált programozás és adatkapszulázás alá tartozik :
Ezeket a változókat azután a fordító vagy tolmács szándékozik elosztani, közvetlenül az eljárás kilépésekor vagy egy szemétgyűjtőn keresztül .
Ugyanakkor előfordul, hogy a tervezés által választott programozó készteti, hogy módosítsa az egyes eljárások, önként vagy sem, „megosztott” változók vagy memória területek, amelyek szerkezetileg független az eljárást. Kiderült, hogy a kényszerítő programozás, ezek a „periférikus” módosítások szerint kijelölt általános kifejezés a mellékhatások (vagy mellékhatások ), amelyek de facto több a szabály, mint kivétel és nagymértékben bonyolítja a programok megértését, következésképpen sok nehézség és hiba okozza őket : valóban, ha elfelejtünk frissíteni bizonyos megosztott adatokat, vagy éppen ellenkezőleg, azokat az összes adat mérése nélkül módosítjuk. , ha a különböző szoftverkomponensek általi hozzárendelések időrendi sorrendje nem megfelelő, vagy ha egy memóriaterületet rossz időben osztanak ki, akkor a program előre nem látható, következetlen vagy akár instabil állapotba kerül, és a programozó gyakran nem képes észlelni az eredetet hiba esetén, és ha ez sikerül, akkor ez súlyos programozás költsége .
A funkcionális nyelvek másik tulajdonsága a referenciális átláthatóság . Ez a kifejezés azt az egyszerű elvet takarja, hogy a program eredménye nem változik, ha egy kifejezést egyforma értékű kifejezéssel cserél le . Ezt az elvet megsértik a mellékhatások esetén, mivel egy ilyen eljárás, nem csupán a bemeneti argumentumaitól függ, nem feltétlenül azonos a program két adott pillanatában.
Vegyünk egy példát. A C , ha n jelöl egy globális változó tartalmazó egész szám, hogy növeljük (tehát a memória cella látható, a teljes programban), és ha Inc (k) egy olyan függvény, amely növeli az értéket N mennyiségével K :
int n = 2; int inc(int k) { /* incrémentation par effet de bord */ n = n + k; return n; } f(inc(1) + inc(1));Ebben a példában az inc (i) függvény nem adja vissza ugyanazt az értéket a két hívás során: az f függvény egyik argumentuma 2 + 1 = 3 , a másik 3 + 1 = 4 értéket fog érni . Ezért lehetetlen helyettesíteni Inc (i) + inc (i) által a 2 * Inc (i) , mert az értéke Inc (i) abban különbözik minden hívás esetében. Ez a viselkedés alapvetően különbözik a matematikai függvény viselkedésétől. Nagy programléptékben ez azt jelenti, hogy az egyik funkció cseréje másikkal változtatásokat tehet szükségessé a program más részein, és szükség lehet a teljes rendszer újbóli tesztelésére., Mert nincs garancia arra, hogy egy ilyen csere nem változtatta meg általános viselkedését. A rendszer komplexitásának növekedésével nő a változás költsége is. Ezzel szemben a referenciális átlátszósági tulajdonság biztosítja, hogy egy függvény más egyenértékűre történő cseréje nem veszélyezteti a program általános viselkedésének módosítását. Más szóval, matematikailag egyenlőek. Ez a tulajdonság megkönnyíti a szoftverek karbantartását. Lehetővé teszi a működési igazolások automatikus alkalmazását is. Végül további előnye, hogy jelentősen csökkenti a végrehajtási sorrend fontosságát, ezt a függvények hívásának sorrendje biztosítja; ennek következménye, hogy egy funkcionális program párhuzamosítása automatikusan elvégezhető, és hogy a fordítók által elvégezhető optimalizációk könnyebben megvalósíthatók.
A funkcionális nyelvek magas szintű adattípusokat és struktúrákat alkalmaznak, mint például a bővíthető listák. Így általában könnyen elvégezhető olyan műveletek, mint a listák összefűzése, vagy egy függvény alkalmazása egy listára - rekurzívan keresett listára - egyetlen kódsorban.
A funkcionális nyelvek hatékony mechanizmusa a magasabb rendű függvények használata . A függvény akkor mondható magasabb rendűnek, ha a függvényeket argumentumként ( visszahívásnak is nevezi ) veheti fel, vagy ennek eredményeként egy függvényt adhat vissza. Azt is mondjuk, hogy a függvények első osztályú objektumok, ami azt jelenti, hogy ugyanolyan egyszerűen kezelhetők, mint az alaptípusok. A funkciókat manipuláló programok vagy függvények matematikában megfelelnek a funkcionálisoknak . Két egyszerű példa a levezetési és integrációs műveletek. A magasabb rendű funkciókat Alonzo Church és Stephen Kleene tanulmányozta az 1930-as években , a lambda-calculus formalizmusából kiindulva , amely számos funkcionális nyelv, nevezetesen a Haskell nyelvének kialakítását befolyásolta . A zárt derékszögű kategóriák elmélete egy másik megközelítést jelent a funkciók jellemzésére, az univerzális probléma fogalmát felhasználva . Az anubisz nyelv ezen az elméleten alapszik.
A 2000-es évek elején a funkcionális programozás kezdett megjelenni az egyetemeken. Az ipari környezetben az Erlang nyelveket (az Ericsson fejlesztette ki a versenyképes programozási igények és a robusztus követelmények szempontjából), a Common Lisp , az OCaml és a Scheme alkalmazásokat. De a funkcionális nyelvek fejlődését korlátozza a kereskedelmi minőségű eszközök és könyvtárak hiánya, és mindenekelőtt a képzett programozók hiánya. Ne feledje, hogy a Microsoft Research által kifejlesztett F # nyelv 2010-ben ingyenes szoftverlicenc alatt érhető el.
Noha a (nem) versenyben résztvevő ICFP diagramjai ennek ellenkezőjét mutatják, a funkcionális nyelvek a XXI. E század első negyedében a lassúság hírében szenvednek, ma teljesen indokolatlanok : bizonyos fordítói rendszerek , mint például a Sztálin fordítók vagy Bigloo, a Common Lisp fordítói , az ML soraiban lévő nyelvek , például OCaml , Haskell vagy akár a CDuce olyan futtatható fájlokat állítanak elő, amelyek átlagos teljesítménye a végrehajtási idő és tér tekintetében összehasonlítható a C vagy a C ++ által gyártottakkal fordítók . A mellékhatások nélküli kód sokkal robusztusabb és könnyebben karbantartható, előnyben részesítjük azt a programot, amelynek memóriakezelését és viselkedés-előrejelzését nehéz lesz elsajátítani, még akkor is, ha ez egy kicsit veszít a hatékonyságból. Ezenkívül meg kell említeni Chris Okasaki tisztán funkcionális adatstruktúrákkal kapcsolatos munkáját is, amelyek hatékonyságában versenyképesek a megváltoztatható struktúrákkal, és jóval meghaladják azokat, amikor a robusztusságról van szó.
Az egyetemeken és az egyes ipari szektorokon kívül az XSLT a funkcionális paradigma népszerűsítésének eszköze lehet. XML- feldolgozásra szánva lehetővé teszi a programozó számára, hogy megtartsa az imperatív vagy tárgynyelveit , miközben felfedez egy másik programozási logikát.
Hasonlóképpen, a Scala és az OCaml nyelvek, amelyeket funkcionális nyelveknek szánnak, lehetővé teszik a programozó számára, hogy szükség van rá, hogy kötelező programozási logikában maradjon.