Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 1 - Úvod do funkcionálního programování

V tomto tutoriálu si ukážeme, co je to funkcionální programování, k čemu je dobré a jak jej plně využijeme.

Funkcionální programování

Funkcionální programování se hodí zejména pro práci s daty, např. na statistiky nebo analýzy a to je také doména funkcionálních jazyků. Pro jejich uplatnění je dnes poměrně velký trh, např. pro finanční společnosti (možná jste slyšeli pojem Big data). Často se používají také na machine learning nebo zpracování přirozeného jazyka. Výrazně zjednodušují paralelismus, což je jeden z důvodů jeho úspěchu. Pro tvorbu klasických programů se ale zpravidla funkcionální programování míchá s "klasickým" imperativním programováním.

Programovací paradigmata

Abychom funkcionální programování pochopili co nejlépe, připomeňme si nejprve jak funguje "klasické" programování a zmiňme si i další konkurenční programátorské paradigma.

Imperativní programování

Nejdříve se ale podívejme, jak se programuje "normálně". Jazyky jako C, Java, Python, C# a další jsou skvělými ukázkami tzv. imperativního způsobu programování. V podstatě říkáme programu, co má dělat. Ukažme si nějaký jednoduchý kód:

int [] pole = {1, 2, 3, 4, 5};

string spocti(int [] a) {
    int b = a.length;
    int c = b – 2;
    System.out.println(c - b);
    string s = "Hurrraaaaaaaaa, je to v kapse";
    return s;
}

Do proměnné a si uložíme pole prvků, které funkce dostane jako parametr. Do b si uložíme délku a, do c si dosadíme b - 2, a pak vytiskneme výsledek. Parametr a značí objekt, který má nějaké vlastnosti a jedním z nich je délka. Zeptání se na délku je konstantní operace, objekt, zde pole, si samo pamatuje, jak je velké, neboť ho předem staticky inicializujeme neboli předem počítači řekneme, jak jej má připravit.

Zatím asi nic nového.

Deklarativní programování

Pro určité typy úloh se ale může hodit jiný přístup. Těch máme dokonce více. Jedním z nich je říci počítači, jak vypadá náš problém. Tomu se říká deklarativní programování, nebo někdy také "logické programování". Prostě popíšeme jaký chceme výsledek, ne postup k jeho dosažení, ten je již na počítači.

Ukázkou deklarativního jazyka je populární SQL, kde neříkáme jak má databáze interně data přesně získat, ale jen specifikujeme jaká data nás ve výsledku zajímají, jak mají být seřazená, jaká mají obsahovat sloupce a podobně. Databáze to za nás pak již vymyslí a vnitřně náš požadavek přeloží na nějaké imperativní cykly a podmínky. Od těch jsme my ale plně odstínění.

Deklarativní programování ovšem není omezené jen na databáze. Nejlepším nástrojem pro ukázku logického programování je programovací jazyk Prolog, jehož jméno pochází z PROgraming in LOGic. Logické programování pochází z matematické logiky, kdy z nějakého stavu lze jasně říci, zda platí či ne. A pokud nelze dokázat, že platí, pak neplatí. Jako ukázku použijeme rodokmen. Ten budeme brát jako nějakou databázi faktů a z nich chceme získat výsledek:

matka(jana,tereza).
matka(jana,jitka).
matka(jitka,anna).
otec(jan,jitka).
otec(jiri,anna).

babicka(Kdo, Koho):-matka(Kdo,X), ( otec(X,Koho) ; matka(X,Koho) ).

Je jasné, že kód se na první pohled zdá jen jako magie, ale hned to snad bude jasnější. (;) a (,) jsou symboly z logiky, kde (,) znamená and (a zároveň) a (;) označuje or (nebo). Závorky si představte jako černou krabičku ("tady strčíme něco dovnitř, tady vyleze výsledek"). Pokud "strčíme" do závorky jméno, program nám řekne, zda je někdo babičkou někoho v tom daném systému. Pokud máme v databázi informace o tom, že je Jana matka Jitky a Jitka matka Anny, pak musí být Jana babička Anny.

Např:

?-babička(anna,bozena).
false.
?-babička(anna,X).
false.
?-babička(jana,X).
X=anna;

Výše se ptáme na následující fakty:

  1. Je Anna babičkou Boženy? Výsledek je false.
  2. Čí babička je Anna? false (ničí)
  3. Čí babička je Jana? Anny

Pokud by tam však tato informace nebyla, program tvrzení popře jako v prvním případě. I kdyby ji tam pouze někdo zapomněl napsat. Podobně jako v SQL zde totiž říkáme, jak má výsledek vypadat místo toho, jak přesně ho vykutáme z dat. V SQL by dotaz na rodokmen mohl vypadat např. takto:

SELECT vnucka FROM babicka-vnucka WHERE babicka = jana

To byl pouze příklad.

V logickém programování jdou velmi dobře řešit stavové problémy, např. sudoku, hádanka Farmář, vlk, koza, zelí a podobné... Tímto se však s logickým/dekla­rativním programováním loučíme, logickému programování tento kurz nenáleží.

Funkcionální programování

My totiž můžeme na programování nahlížet ještě z jiné strany. Představme si program jako jednu dlouhou funkci, která něco vezme na vstupu a vrátí výsledek. Mějme např. funkci (plus), která nám sečte dvě čísla a funkci (převrať), která převrátí číslo, tedy z 21 nám udělá 12 atd... Složením funkcí nám vznikne funkce magie(x,y) = prevrat.secti(x,y), která vezme dvě čísla, sečte je a výsledek obrátí. (Matematicky se "vláček" posouvá zprava doleva). Funkce magie(9,8) = 71, magie(4,5) = 9, magie(10,0) = 9 atd...

Tento styl se v mnohém podobá logickému programování, ale mnohonásobně ho předčí elegancí a efektivitou. Chtějme např. program, který nám vrátí v poli všechny dělitele nějakého čísla:

dejMiDelitele n =  [ x | x <- [1 .. n] , n `mod` x == 0 ]

Jednoduše popíšeme, co chceme dělat. Máme horní hranici a chceme všechna čísla od 1 do té hranice, pro která platí, že číslo modulo x je rovno 0, neboli x je dělitelem čísla n. Využití funkcionálního programování je tedy nasnadě. Podobný kód s ním dokážeme psát mnohem efektivněji a to bez vedlejších efektů. Co to znamená?

Imperativní jazyky pracují s dosazováním do proměnných a s manipulací s nimi. Ať již proměnnou zmenšíme, zvětšíme, pošleme na zásobník, uložíme do pole, vytiskneme atd., pracujeme s pamětí. To je nebezpečné a někdy také zdlouhavé. Funkcionální programovaní na to jde z druhé strany. Vyrobíme si "mašinku", do které něco vsuneme a na konci z ní vypadne výsledek. Díky tomu nemáme problém např. s paralelizmem, prostě dáme vedle sebe 3 mašinky, dáme do nich 3 vstupy a dostaneme 3 výstupy. A pokud děláme Big data, určitě je chceme dělat paralelně, protože by to jinak trvalo opravdu dlouho :)

Dále je zde jiný způsob psaní programů. U funkcí chceme, aby na jasný vstup dala jasný výstup. To má za následek jednoduché ladění programů, neboť pokud každá funkce dělá to, co má, pro daný výsledek je jen pospojujeme za sebe. Druhým velmi příjemným důsledkem je, že skládáme za sebe malé programy. Většinou se vejdou do 10 řádek. Opět, výsledek se dostaví hned, jakmile vám začne vstup házet nečekaný výstup.

Vývojové prostředí

Nyní se ještě zmíníme o prostředí, které budeme používat. Je to GHCi a najdete ho jak pro Windows i Linux. Výhodou je jeho jednoduchost. I pokud nejste na programování v konzoli zvyklí, přesto doporučuji tento nástroj, protože je to přesná ukázka toho, co by funkcionální programování mělo dělat. To, co má, a ani o trochu navíc :) Přesto nezoufejte. Kromě kompileru potřebujeme ještě textový editor, na kterém budeme psát naše funkce. Na to stačí poznámkový blok, na Linuxu je na to vhodný VIM, který podporuje Haskell syntaxi, nebo spousta dalších nástrojů.

Funkcionální programovací jazyky

Co se týče toho, co je a co není funkcionální jazyk, je třeba si ujasnit, co od funkcionálního jazyka očekáváme. Pokud chceme, aby v něm nešlo psát procedurálně, pak nám mnoho jazyků nezbude. Například Haskell je čistě funkcionální jazyk. Jazyky jako Dart, Scala, F# jsou funkcionální. Pokud však definici rozšíříme na to, zda v jazyce lze psát funkcionálně, pak tam patří jazyky jako C#, Java, Python atd... Těmto jazykům se proto říká často multiparadigmatické a v praxi je funkcionální programování opravdu často s imperativním programováním kombinované. Danou část programu prostě napíšeme přístupem, který je pro ní efektivnější. Funkcionální programování multiparadigmatické jazyky podporují pomocí tzv. lambda výrazů. K tomu se však dostaneme.

Pokračovat budeme příště v lekci První funkce v Haskell.


 

Všechny články v sekci
Haskell
Přeskočit článek
(nedoporučujeme)
První funkce v Haskell
Článek pro vás napsal Ondřej Michálek
Avatar
Uživatelské hodnocení:
17 hlasů
Autor se věnuje teoretické informatice. Ve svých volných chvílích nepohrdne šálkem dobrého čaje, kaligrafickým brkem a foukací harmonice.
Aktivity