November Black Friday C/C++ week
Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
Pouze tento týden sleva až 80 % na e-learning týkající se C/C++

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

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

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.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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.


 

 

Článek pro vás napsal Tricerator
Avatar
Jak se ti líbí článek?
4 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.
Všechny články v sekci
Haskell
Miniatura
Následující článek
První funkce v Haskell
Aktivity (5)

 

 

Komentáře

Avatar
Taskkill
Redaktor
Avatar
Taskkill:8. listopadu 17:17

Článek o fp na itn je něco, na co čekám už hodně dlouho.

Líbí se mi že si zmínil i logické programování - to je koncept, který si rozhodně zaslouží větší pozornost mezi začínajícími programátory.

Trošku mě zamrzelo že nebyl zmíněn Lisp jako historický průkopník fp a současně i jedna z největších inspirací pro mnoho současných jazyků. Ale z volby Haskellu mám velkou radost, je to skvělý jazyk - bylo by super někdy v budoucnu ukázat i Elm - je podle mě obrovsky přínosný pro varianci web ekosystému.

Hodně štěstí s psaním, budu tenhle seriál sledovat dál.

 
Odpovědět
8. listopadu 17:17
Avatar
ZemiakSK
Člen
Avatar
ZemiakSK:11. listopadu 12:51

Tomu se říká deklarativní programování, nebo někdy také "logické programování"

Deklarativne a logické programovanie nie je to isté

Logické programovanie je len poddruhom deklarativneho paradigmatu
(Rovnako , procedurálne alebo objektovo orientované programovanie je len poddruhom imperativneho paradigmatu)

(,) znamená and

Nie je nahodou and bodka (.)?
Je to aj v príkladoch

 
Odpovědět
11. listopadu 12:51
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na ZemiakSK
Taskkill:13. listopadu 10:45

Nie je nahodou and bodka (.)?

Nn. Je to napsané správně. Stejně tak jsou příklady správně.

Tečka ukončuje klauzuli. [1]

Čárka vytváří sekvenci predikátů, které všechny musí platit - tedy AND. [2]

The comma between the two conditions can be considered as a logical-AND operator.

 
Odpovědět
13. listopadu 10:45
Avatar
ZemiakSK
Člen
Avatar
Odpovídá na Taskkill
ZemiakSK:14. listopadu 9:45

Prepáč , pomýlil som sa , máš pravdu
https://cs.wikipedia.org/…movací_jazyk)

 
Odpovědět
14. listopadu 9:45
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 4 zpráv z 4.