Funkcionální programování - Functional programming

Ve vědě o počítačích , funkcionální programování je programovací paradigma , kde jsou programy konstruovány aplikací a skládání funkcí . Je to deklarativní programovací paradigma, ve kterém definice funkce jsou stromy z výrazů , které jsou mapovány hodnoty k jiným hodnotám, nikoli posloupnost naléhavých závěrky které aktualizace na běžící stav programu.

Ve funkčním programování jsou funkce považovány za občany první třídy , což znamená, že je lze svázat se jmény (včetně místních identifikátorů ), předávat jako argumenty a vracet z jiných funkcí, stejně jako to dokáže jakýkoli jiný datový typ . To umožňuje programům psát deklarativním a skládatelným stylem, kde jsou malé funkce kombinovány modulárním způsobem.

Funkční programování je někdy považováno za synonymum čistě funkčního programování , podmnožiny funkčního programování, které považuje všechny funkce za deterministické matematické funkce nebo čisté funkce . Když je s některými danými argumenty volána čistá funkce, vždy vrátí stejný výsledek a nemůže být ovlivněna žádným měnitelným stavem ani jinými vedlejšími efekty . To je v kontrastu s nečistými procedurami , běžnými v imperativním programování , které mohou mít vedlejší účinky (například změna stavu programu nebo převzetí vstupu od uživatele). Zastánci čistě funkčního programování tvrdí, že omezením vedlejších účinků mohou mít programy méně chyb , snadnější ladění a testování a budou vhodnější pro formální ověřování .

Funkční programování má své kořeny v akademickém světě , které se vyvíjí z lambda kalkulu , formálního systému výpočtu založeného pouze na funkcích. Funkční programování bylo historicky méně populární než programování imperativní, ale mnoho funkčních jazyků dnes vidí využití v průmyslu a vzdělávání, včetně Common Lisp , Scheme , Clojure , Wolfram Language , Racket , Erlang , Elixir , OCaml , Haskell a F# . Funkční programování je také klíčové pro některé jazyky, které dosáhly úspěchu v konkrétních doménách, jako je JavaScript na webu, R ve statistikách, J , K a Q ve finanční analýze a XQuery / XSLT pro XML . Deklarativní jazyky specifické pro doménu, jako jsou SQL a Lex / Yacc, používají některé prvky funkčního programování, například neumožňují měnitelné hodnoty . Mnoho dalších programovacích jazyků navíc podporuje programování ve funkčním stylu nebo implementovalo funkce z funkčního programování, jako je C ++ 11 , Kotlin , Perl , PHP , Python , Go , Rust , Raku , Scala a Java (od Javy 8) ) .

Dějiny

Lambda kalkulu , který byl vypracován v roce 1930 Alonzo Church , je formální systém z výpočtu postavený z aplikace funkce . V roce 1937 Alan Turing dokázal, že lambda kalkul a Turingovy stroje jsou ekvivalentní modely výpočtu, což ukazuje, že lambda kalkul je Turingův kompletní . Lambda kalkul tvoří základ všech funkčních programovacích jazyků. Ekvivalentní teoretickou formulaci, kombinační logiku , vypracovali Moses Schönfinkel a Haskell Curry ve 20. a 30. letech minulého století.

Church později vyvinul slabší systém, jednoduše napsaný lambda kalkul , který rozšířil lambda kalkul přiřazením typu ke všem výrazům. To tvoří základ pro staticky napsané funkční programování.

První funkční programovací jazyk, LISP , byl vyvinut koncem padesátých let pro sérii vědeckých počítačů IBM 700/7000 Johnem McCarthym na Massachusetts Institute of Technology (MIT). Funkce LISP byly definovány pomocí lambda notace Church, rozšířené o konstrukci štítku, která umožňuje rekurzivní funkce. Lisp poprvé představil mnoho paradigmatických rysů funkčního programování, ačkoli rané Lispy byly jazyky s více paradigmaty , a jak se vyvíjela nová paradigmata, začlenila podporu mnoha programovacích stylů. Pozdější dialekty, jako Scheme a Clojure , a odnože jako Dylan a Julia , se snažily zjednodušit a racionalizovat Lisp kolem čistě funkčního jádra, zatímco Common Lisp byl navržen tak, aby zachoval a aktualizoval paradigmatické rysy mnoha starších dialektů, které nahradil.

Information Processing Language (IPL), 1956, je někdy citován jako první počítačový funkční programovací jazyk. Je to jazyk ve stylu sestavení pro manipulaci se seznamy symbolů. Má představu o generátoru , což je funkce, která přijímá funkci jako argument, a protože se jedná o jazyk na úrovni sestavení, kód mohou být data, takže IPL lze považovat za funkce vyššího řádu. Velmi se však spoléhá na strukturu seznamu mutujících a podobné imperativní funkce.

Kenneth E. Iverson vyvinul APL na počátku šedesátých let, popsaný ve své knize z roku 1962 Programovací jazyk ( ISBN  9780471430148 ). APL byl primární vliv na John Backus ‚s FP . V časných 1990, Iverson a Roger Hui vytvořen J . V polovině 1990, Arthur Whitney , kdo předtím pracoval s Iverson, vytvořil K , který se používá běžně na finančních průmyslu spolu s jeho potomka Q .

John Backus představil FP ve své přednášce Turing Award z roku 1977 „Lze programování osvobodit od stylu von Neumanna ? Funkční styl a jeho algebra programů“. Funkční programy definuje jako budované hierarchickým způsobem pomocí „kombinování forem“, které umožňují „algebru programů“; v moderním jazyce to znamená, že funkční programy dodržují princip kompozičnosti . Backusův článek popularizoval výzkum funkčního programování, ačkoli zdůrazňoval spíše programování na úrovni funkcí než styl lambda-kalkulu, který je nyní spojen s funkčním programováním.

Jazyk ML z roku 1973 vytvořil Robin Milner na univerzitě v Edinburghu a David Turner vyvinul jazyk SASL na univerzitě v St. Andrews . Také v Edinburghu v 70. letech vyvinuli Burstall a Darlington funkční jazyk NPL . NPL byla založena na Kleeneových rekurzních rovnicích a byla poprvé představena v jejich práci na transformaci programu. Burstall, MacQueen a Sannella poté začlenili kontrolu polymorfního typu z ML, aby vytvořili jazyk Hope . ML se nakonec vyvinul do několika dialektů, z nichž nejběžnější jsou nyní OCaml a Standard ML .

V 70. letech 20. století Guy L. Steele a Gerald Jay Sussman vyvinuli schéma , jak je popsáno v Lambda Papers a učebnici Struktura a interpretace počítačových programů z roku 1985 . Scheme byl první dialekt lispu, který používal lexikální scoping a vyžadoval optimalizaci ocasu , funkce podporující funkční programování.

V osmdesátých letech vyvinul Per Martin-Löf intuicionalistickou teorii typů (nazývanou také teorie konstruktivního typu), která spojovala funkční programy s konstruktivními důkazy vyjádřenými jako závislé typy . To vedlo k novým přístupům k interaktivnímu dokazování teorémů a ovlivnilo to vývoj dalších funkčních programovacích jazyků.

Líný funkční jazyk, Miranda , vyvinutý Davidem Turnerem, se původně objevil v roce 1985 a měl na Haskella silný vliv . S tím, že Miranda je proprietární, začal Haskell v roce 1987 konsensem vytvořit otevřený standard pro výzkum funkčního programování; implementační verze probíhají od roku 1990.

V poslední době našel použití ve výklencích, jako je parametrická CAD s laskavým svolením jazyka OpenSCAD postaveného na geometrickém rámci CSG, ačkoli jeho omezení opětovného přiřazení hodnot (všechny hodnoty jsou považovány za konstanty) vedlo ke zmatku mezi uživateli, kteří nejsou obeznámeni s funkčním programováním jako koncept.

Funkční programování se nadále používá v komerčním prostředí.

Pojmy

Řada konceptů a paradigmat je specifická pro funkční programování a obecně cizí imperativnímu programování (včetně objektově orientovaného programování ). Programovací jazyky však často obstarávají několik programovacích paradigmat, takže programátoři používající „většinou imperativní“ jazyky možná některé z těchto konceptů využili.

Prvotřídní funkce a funkce vyššího řádu

Funkce vyššího řádu jsou funkce, které mohou buď jiné funkce brát jako argumenty, nebo je vracet jako výsledky. V počtu je příkladem funkce vyššího řádu diferenciální operátor , který vrací derivaci funkce .

Funkce vyššího řádu úzce souvisí s funkcemi první třídy v tom smyslu, že funkce vyššího řádu a funkce první třídy umožňují funkce jako argumenty a výsledky jiných funkcí. Rozdíl mezi těmito dvěma je jemný: „vyššího řádu“ popisuje matematický koncept funkcí, které fungují na jiných funkcích, zatímco „first-class“ je termín pro počítačové vědy pro entity programovacího jazyka, které nemají žádné omezení v jejich používání (tedy první -class funkce se mohou objevit kdekoli v programu, které mohou mít jiné prvotřídní entity, jako jsou čísla, včetně argumentů pro jiné funkce a jejich návratových hodnot).

Funkce vyššího řádu umožňují částečnou aplikaci nebo currying , což je technika, která aplikuje funkci na své argumenty po jednom, přičemž každá aplikace vrací novou funkci, která přijímá další argument. To umožňuje programátorovi stručně vyjádřit například funkci nástupce jako operátor sčítání částečně aplikovaný na přirozenou jedničku.

Čisté funkce

Čisté funkce (nebo výrazy) nemají žádné vedlejší účinky (paměť nebo I/O). To znamená, že čisté funkce mají několik užitečných vlastností, z nichž mnohé lze použít k optimalizaci kódu:

  • Pokud není použit výsledek čistého výrazu, lze jej odebrat bez ovlivnění dalších výrazů.
  • Pokud je volána čistá funkce s argumenty, které nezpůsobují žádné vedlejší efekty, je výsledek vzhledem k tomuto seznamu argumentů (někdy nazývaný referenční transparentnost nebo idempotence ) konstantní , tj. Opětovné volání čisté funkce se stejnými argumenty vrátí stejný výsledek. (To může povolit optimalizaci ukládání do mezipaměti, jako je memoizace .)
  • Pokud mezi dvěma čistými výrazy neexistuje žádná závislost na datech, lze jejich pořadí obrátit nebo je lze provádět souběžně a nemohou navzájem kolidovat (jinými slovy, vyhodnocení jakéhokoli čistého výrazu je bezpečné pro vlákna ).
  • Pokud celý jazyk nepovoluje vedlejší efekty, lze použít jakoukoli strategii hodnocení; to dává kompilátoru volnost k přeskupení nebo kombinaci vyhodnocení výrazů v programu (například pomocí odlesňování ).

Zatímco většina kompilátorů pro imperativní programovací jazyky detekuje čisté funkce a provádí eliminaci běžných podvýrazů pro volání čistých funkcí, nemohou to vždy dělat u předkompilovaných knihoven, které tyto informace obecně nevystavují, čímž se zabrání optimalizaci, která zahrnuje tyto externí funkce. Některé kompilátory, například gcc , přidávají další klíčová slova pro programátora, aby explicitně označili externí funkce jako čisté, aby takové optimalizace umožnily. Fortran 95 také umožňuje označit funkce jako čisté . C ++ 11 přidalo constexprklíčové slovo s podobnou sémantikou.

Rekurze

Iterace (smyčka) ve funkčních jazycích se obvykle provádí pomocí rekurze . Rekurzivní funkce se samy vyvolávají, takže se operace může opakovat, dokud nedosáhne na základní případ . Obecně platí, že rekurze vyžaduje udržování zásobníku , který lineárně spotřebovává prostor do hloubky rekurze. To by mohlo způsobit, že bude použití rekurze neúměrně drahé místo imperativních smyček. Speciální formu rekurze známou jako rekurze ocasu však může kompilátor rozpoznat a optimalizovat do stejného kódu, který se používá k implementaci iterace v imperativních jazycích. Optimalizaci rekurze ocasu lze mimo jiné implementovat transformací programu do stylu předávání pokračování během kompilace.

Scheme standardní jazyk vyžaduje implementace podporovat správné ocas rekurzi, což znamená, že musí umožnit nespoutaný počet aktivních koncových hovorů. Správná rekurze ocasu není pouhou optimalizací; je to jazyková funkce, která zajišťuje uživatelům, že mohou použít rekurzi k vyjádření smyčky a přitom by to bylo bezpečné pro prostor. Kromě toho, na rozdíl od svého názvu, představuje všechna volání ocasu, nejen rekurzi ocasu. Zatímco správná rekurze ocasu je obvykle implementována přeměnou kódu na imperativní smyčky, implementace jej mohou implementovat jinými způsoby. Například CHICKEN záměrně udržuje zásobník a nechává jej přetečit . Když se to však stane, jeho garbage collector si nárokuje místo zpět, což umožní neomezený počet aktivních volání ocasu, přestože se z rekurze ocasu nestane smyčka.

Běžné vzorce rekurze lze abstrahovat pomocí funkcí vyššího řádu, přičemž nejzjevnějšími příklady jsou katamorfismy a anamorfismy (neboli „záhyby“ a „rozvinutí“). Tato schémata rekurze hrají roli analogickou s integrovanými řídicími strukturami, jako jsou smyčky v imperativních jazycích .

Většina funkčních programovacích jazyků pro obecné účely umožňuje neomezenou rekurzi a jsou Turingovo úplné , což činí problém zastavení nerozhodnutelným , může způsobit nesrozumitelnost rovníkového uvažování a obecně vyžaduje zavedení nekonzistence do logiky vyjádřené jazykovým typovým systémem . Některé jazyky zvláštního účelu, jako je Coq, umožňují pouze fundovanou rekurzi a silně se normalizují (nekončící výpočty lze vyjádřit pouze nekonečnými proudy hodnot nazývanými kodata ). V důsledku toho tyto jazyky nejsou Turingovy úplné a vyjádření určitých funkcí v nich je nemožné, ale přesto mohou vyjadřovat širokou škálu zajímavých výpočtů, aniž by se vyhnuly problémům, které přináší neomezená rekurze. Funkční programování omezené na fundovanou rekurzi s několika dalšími omezeními se nazývá totální funkční programování .

Přísné versus nepřísné hodnocení

Funkční jazyky lze kategorizovat podle toho, zda používají přísné (nedočkavé) nebo nestříhané (líné) hodnocení, koncepty, které odkazují na způsob zpracování argumentů funkcí při vyhodnocování výrazu. Technický rozdíl je v denotační sémantice výrazů obsahujících selhávající nebo divergentní výpočty. Při přísném vyhodnocení selže vyhodnocení jakéhokoli výrazu obsahujícího selhávající podterm. Například výraz:

print length([2+1, 3*2, 1/0, 5-4])

selže pod přísným hodnocením kvůli dělení nulou ve třetím prvku seznamu. Při opožděném hodnocení vrátí funkce length hodnotu 4 (tj. Počet položek v seznamu), protože při jejím vyhodnocení se nepokouší vyhodnotit výrazy tvořící seznam. Stručně řečeno, přísné hodnocení vždy plně vyhodnotí argumenty funkce před vyvoláním funkce. Opožděné vyhodnocení nevyhodnocuje argumenty funkce, pokud jejich hodnoty nejsou nutné k vyhodnocení samotného volání funkce.

Obvyklou implementační strategií pro líné hodnocení ve funkčních jazycích je redukce grafů . Líné hodnocení se ve výchozím nastavení používá v několika čistě funkčních jazycích, včetně Mirandy , Clean a Haskell .

Hughes 1984 argumentuje pro líné hodnocení jako mechanismus pro zlepšení modularity programu oddělením problémů zjednodušením nezávislé implementace producentů a spotřebitelů datových toků. Launchbury 1993 popisuje některé potíže, které líné hodnocení přináší, zejména při analýze požadavků programu na úložiště, a navrhuje operační sémantiku, která by při takové analýze pomohla. Harper 2009 navrhuje zahrnout jak přísné, tak líné hodnocení ve stejném jazyce, přičemž k jejich rozlišení použijte typový systém jazyka.

Typové systémy

Zejména od vývoje odvozování typu Hindley – Milner v 70. letech 20. století mají funkční programovací jazyky tendenci používat typovaný lambda kalkul , odmítají všechny neplatné programy v době kompilace a riskují falešně pozitivní chyby , na rozdíl od netypovaného lambda kalkulu , který akceptuje všechny platné programy v době kompilace a riskují falešně negativní chyby , používané v Lispu a jeho variantách (jako je Scheme ), přestože odmítají všechny neplatné programy za běhu, když jsou informace dostatečné k neodmítnutí platných programů. Použití algebraických datových typů usnadňuje manipulaci se složitými datovými strukturami; přítomnost silné kontroly typu v době kompilace činí programy spolehlivějšími v případě neexistence jiných technik spolehlivosti, jako je vývoj na základě testů , zatímco odvozování typu osvobozuje programátora od nutnosti ručně deklarovat typy kompilátoru ve většině případů.

Některé výzkumně orientované funkční jazyky, jako jsou Coq , Agda , Cayenne a Epigram, jsou založeny na intuicionistické teorii typů , která umožňuje typům záviset na termínech. Takové typy se nazývají závislé typy . Tyto typové systémy nemají odvození rozhodnutelného typu a je obtížné je pochopit a programovat. Ale závislé typy mohou vyjadřovat libovolné výroky v logice vyššího řádu . Díky Curry-Howardovu izomorfismu se pak dobře napsané programy v těchto jazycích stávají prostředkem pro psaní formálních matematických důkazů, ze kterých může překladač generovat certifikovaný kód . Přestože se tyto jazyky zajímají hlavně o akademický výzkum (včetně formalizované matematiky ), začaly se používat i ve strojírenství. Compcert je kompilátor pro podmnožinu programovacího jazyka C, který je napsán v Coq a formálně ověřen.

Omezenou formu závislých typů nazývanou generalizované algebraické datové typy (GADT) lze implementovat způsobem, který poskytuje některé výhody závisle typovaného programování a zároveň se vyhýbá většině jeho nepříjemností. GADT jsou k dispozici v kompilátoru Glasgow Haskell , v OCaml a ve Scale a byly navrženy jako doplňky do jiných jazyků včetně Javy a C#.

Referenční transparentnost

Funkční programy nemají přiřazovací příkazy, to znamená, že hodnota proměnné ve funkčním programu se po definování nikdy nezmění. Tím se eliminuje jakákoli šance na vedlejší účinky, protože jakoukoli proměnnou lze nahradit její skutečnou hodnotou v kterémkoli místě spuštění. Funkční programy jsou tedy referenčně transparentní.

Zvažte příkaz přiřazení Cx = x * 10 , tím se změní hodnota přiřazená proměnné x. Řekněme, že počáteční hodnota xbyla 1, pak dvě po sobě jdoucí hodnocení proměnných xvýnosů 10a 100resp. Je zřejmé, že nahrazení x = x * 10buďto 10nebo nebo 100dává programu jiný význam, a proto výraz není referenčně transparentní. Ve skutečnosti nejsou příkazy přiřazení nikdy referenčně transparentní.

Nyní zvažte jinou funkci, jako je transparentní, protože implicitně nemění vstup x, a proto nemá žádné takové vedlejší účinky . Funkční programy využívají výhradně tento typ funkcí, a jsou tedy referenčně transparentní. int plusone(int x) {return x+1;}

Datové struktury

Čistě funkční datové struktury jsou často zastoupeny jiným způsobem než jejich imperativní protějšky. Například pole s konstantními časy přístupu a aktualizací je základní součástí většiny imperativních jazyků a mnoho imperativních datových struktur, jako je tabulka hash a binární halda , je založeno na polích. Pole lze nahradit mapami nebo seznamy náhodného přístupu, které sice připouštějí čistě funkční implementaci, ale mají logaritmický přístup a časy aktualizací. Čistě funkční datové struktury mají perzistenci , což je vlastnost zachování předchozích verzí datové struktury bez úprav. V Clojure se používají trvalé datové struktury jako funkční alternativy k jejich imperativním protějškům. Trvalé vektory například používají stromy k částečné aktualizaci. Voláním metody insert dojde k vytvoření některých, ale ne všech uzlů.

Srovnání s imperativním programováním

Funkční programování se velmi liší od programování imperativního . Nejvýznamnější rozdíly vyplývají ze skutečnosti, že funkční programování se vyhýbá vedlejším efektům , které se používají v imperativním programování k implementaci stavu a I/O. Čistě funkční programování zcela zabraňuje vedlejším efektům a poskytuje referenční transparentnost.

Funkce vyššího řádu se ve starším imperativním programování používají jen zřídka. Tradiční imperativní program může používat smyčku k procházení a úpravám seznamu. Na druhou stranu funkční program by pravděpodobně používal funkci „mapy“ vyššího řádu, která přebírá funkci a seznam, generuje a vrací nový seznam použitím funkce na každou položku seznamu.

Imperativní vs. funkční programování

Následující dva příklady (napsané v JavaScriptu ) dosahují stejného účinku: vynásobí všechna sudá čísla v poli 10 a všechna sečtou, přičemž konečný součet uloží do proměnné „výsledek“.

Tradiční imperativní smyčka:

const numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = 0;
for (let i = 0; i < numList.length; i++) {
  if (numList[i] % 2 === 0) {
    result += numList[i] * 10;
  }
}

Funkční programování s funkcemi vyššího řádu:

const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
               .filter(n => n % 2 === 0)
               .map(a => a * 10)
               .reduce((a, b) => a + b);

Simulující stav

Existují úkoly (například udržování zůstatku na bankovním účtu), které se často zdají nejpřirozeněji implementovány se státem. Čistě funkční programování provádí tyto úkoly a I/O úlohy, jako je přijímání vstupu uživatele a tisk na obrazovku, jiným způsobem.

Čistě funkční programovací jazyk Haskell je implementuje pomocí monád odvozených z teorie kategorií . Monády nabízejí způsob, jak abstraktním způsobem abstrahovat určité typy výpočetních vzorců, včetně (ale nejen) modelování výpočtů s proměnlivým stavem (a dalšími vedlejšími efekty, jako je I/O), aniž by došlo ke ztrátě čistoty. Zatímco existující monády mohou být v programu snadno aplikovatelné, vzhledem k příslušným šablonám a příkladům je pro mnoho studentů koncepčně obtížné porozumět, např. Když jsou požádáni o definování nových monad (což je někdy nutné u určitých typů knihoven).

Funkční jazyky také simulují stavy tím, že procházejí kolem neměnných stavů. To lze provést tak, že funkce přijme stav jako jeden ze svých parametrů a vrátí nový stav spolu s výsledkem, přičemž ponechá starý stav beze změny.

Nečisté funkční jazyky obvykle obsahují přímější způsob správy měnitelného stavu. Clojure například používá spravované odkazy, které lze aktualizovat použitím čistých funkcí na aktuální stav. Tento druh přístupu umožňuje měnitelnost a současně podporuje používání čistých funkcí jako upřednostňovaného způsobu vyjádření výpočtů.

Pro sledování vedlejších účinků v programech byly vyvinuty alternativní metody, jako je Hoareova logika a jedinečnost . Některé moderní výzkumné jazyky používají efektové systémy , aby byla přítomnost vedlejších účinků výslovná.

Problémy s účinností

Funkční programovací jazyky jsou obvykle méně efektivní v používání CPU a paměti než imperativní jazyky, jako jsou C a Pascal . To souvisí se skutečností, že některé měnitelné datové struktury, jako jsou pole, mají velmi jednoduchou implementaci pomocí současného hardwaru. K plochým polím lze přistupovat velmi efektivně pomocí hluboce propojených procesorů, efektivně je předem načíst prostřednictvím mezipaměti (bez složitého pronásledování ukazatelů ) nebo je lze zpracovávat pomocí pokynů SIMD. Rovněž není snadné vytvořit jejich stejně efektivní univerzálně použitelné neměnné protějšky. U čistě funkčních jazyků je nejhorší zpomalení logaritmické v počtu použitých paměťových buněk, protože proměnlivá paměť může být reprezentována čistě funkční datovou strukturou s logaritmickou přístupovou dobou (například vyvážený strom). Taková zpomalení však nejsou univerzální. U programů, které provádějí intenzivní numerické výpočty, jsou funkční jazyky jako OCaml a Clean jen o něco pomalejší než C podle hry The Computer Language Benchmarks Game . Pro programy, které zpracovávají velké matice a vícerozměrné databáze , byly navrženy matice funkčních jazyků (například J a K ) s optimalizací rychlosti.

Neměnnost dat může v mnoha případech vést k efektivitě provádění tím, že kompilátor umožní předpokladům, které jsou v imperativním jazyce nebezpečné, čímž se zvýší příležitosti pro vloženou expanzi .

Opožděné hodnocení může také urychlit program, a to i asymptoticky, zatímco jej může zpomalit nanejvýš o konstantní faktor ( při nesprávném použití však může způsobit nevracení paměti ). Launchbury 1993 pojednává o teoretických problémech souvisejících s úniky paměti z líného hodnocení a O'Sullivan et al. 2008 poskytnout několik praktických rad pro jejich analýzu a opravu. Nejobecnější implementace opožděného hodnocení, využívající rozsáhlé využití dereferencovaného kódu a dat, však na moderních procesorech s hlubokými kanály a víceúrovňovými mezipaměti (kde mezipaměť může stát stovky cyklů) funguje špatně.

Funkční programování v nefunkčních jazycích

Funkční styl programování je možné použít v jazycích, které nejsou tradičně považovány za funkční jazyky. Například D i Fortran 95 výslovně podporují čisté funkce.

JavaScript , Lua , Python a Go měly od svého vzniku prvotřídní funkce . Python měl v roce 1994 podporu pro „ lambda “, „ mapu “, „ zmenšení “ a „ filtr “, stejně jako uzávěry v Pythonu 2.2, ačkoli Python 3 odsunul „zmenšit“ do functoolsmodulu standardní knihovny. Prvotřídní funkce byly zavedeny do dalších běžných jazyků, jako je PHP 5.3, Visual Basic 9 , C# 3.0, C ++ 11 a Kotlin .

V PHP , anonymní třídy , uzávěry a Lambdy jsou plně podporovány. Knihovny a jazyková rozšíření pro neměnné datové struktury jsou vyvíjeny s cílem pomoci programování ve funkčním stylu.

V Javě , anonymní třídy někdy může být použit k simulaci uzávěry ; anonymní třídy však nejsou vždy vhodnou náhradou za uzávěry, protože mají omezenější možnosti. Java 8 podporuje výrazy lambda jako náhradu za některé anonymní třídy.

V jazyce C # , anonymní třídy nejsou nutné, protože uzávěry a Lambdy jsou plně podporovány. Knihovny a jazyková rozšíření pro neměnné datové struktury jsou vyvíjeny s cílem pomoci programování ve funkčním stylu v C#.

Mnoho objektově orientovaných návrhových vzorů je vyjádřeno funkčním programováním: například strategický vzor jednoduše diktuje použití funkce vyššího řádu a vzor návštěvníka zhruba odpovídá katamorfismu neboli skládání .

Podobně je myšlenka neměnných dat z funkčního programování často součástí imperativních programovacích jazyků, například n -tice v Pythonu, což je neměnné pole, a Object.freeze () v JavaScriptu.

Aplikace

Tabulky

Tabulky lze považovat za formu čistého funkčního programovacího systému s nulovým řádem a přísným hodnocením. Tabulky však obecně postrádají funkce vyššího řádu, stejně jako opětovné použití kódu a v některých implementacích také chybí rekurze. Pro tabulkové programy bylo vyvinuto několik rozšíření, které umožňují funkce vyššího řádu a opakovaně použitelné funkce, ale zatím zůstávají primárně akademické povahy.

Academia

Funkční programování je aktivní oblastí výzkumu v oblasti teorie programovacích jazyků . Existuje několik recenzovaných míst publikace zaměřených na funkční programování, včetně Mezinárodní konference o funkčním programování , Časopisu funkčního programování a Sympozia o trendech ve funkčním programování .

Průmysl

Funkční programování se uplatnilo v celé řadě průmyslových aplikací. Například Erlang , který vyvinula švédská společnost Ericsson na konci 80. let, původně sloužil k implementaci telekomunikačních systémů odolných proti chybám , ale od té doby se stal oblíbeným pro budování řady aplikací ve společnostech jako Nortel , Facebook , Électricité de Francie a WhatsApp . Scheme , dialekt Lispu , byl použit jako základ pro několik aplikací na počátečních počítačích Apple Macintosh a byl aplikován na problémy, jako je tréninkový simulační software a ovládání teleskopu . OCaml , který byl představen v polovině devadesátých let, zaznamenal komerční využití v oblastech, jako je finanční analýza, ověřování řidičů , programování průmyslových robotů a statická analýza vestavěného softwaru . Haskell , ačkoli byl původně zamýšlen jako výzkumný jazyk, byl také aplikován řadou společností v oblastech, jako jsou letecké systémy, hardwarový design a webové programování.

Mezi další funkční programovací jazyky, které se v průmyslu uplatnily , patří Scala , F# , Wolfram Language , Lisp , Standard ML a Clojure .

Funkční „platformy“ byly populární ve financích pro analýzu rizik (zejména u větších investičních bank). Rizikové faktory jsou kódovány jako funkce, které tvoří vzájemně závislé grafy (kategorie) pro měření korelací v tržních posunech, ne na rozdíl od optimalizace základů podle Gröbnera, ale také pro dodržování předpisů, jako je komplexní kapitálová analýza a kontrola . Vzhledem k použití variací OCAML nebo CAML ve financích jsou tyto systémy někdy považovány za související s kategoriálním abstraktním strojem nebo CAM. Funkční programování je skutečně silně ovlivněno teorií kategorií .

Vzdělávání

Mnoho univerzit vyučuje nebo vyučovalo funkční programování jako součást svých bakalářských titulů z informatiky. Někteří to používají jako úvod do programování, zatímco jiní to učí po výuce imperativního programování.

Mimo informatiku se funkční programování používá jako metoda pro výuku řešení problémů, algebry a geometrických pojmů. Rovněž byl použit jako nástroj pro výuku klasické mechaniky ve Struktuře a interpretaci klasické mechaniky .

Viz také

Reference

Další čtení

externí odkazy

Poslechněte si tento článek ( 28 minut )
Mluvená ikona Wikipedie
Tento zvukový soubor byl vytvořen z revize tohoto článku ze dne 25. srpna 2011 a neodráží následné úpravy. ( 2011-08-25 )