Obsah
1. Řídicí konstrukce v programovacím jazyku OCaml
2. Rozhodovací konstrukce if-then-else
3. Náhrada if-then-else za pattern matching
4. Forma zápisu konstrukce if-then-else
6. Náhrada za pattern matching s podmínkami
7. Větší množství příkazů ve větvích: blok begin-end
8. Programové smyčky v jazyku OCaml
12. Vnořená podmínka uvnitř smyčky
13. Programová smyčka typu while
14. Korektní použití smyčky while
16. Operace typu zip zkombinovaná s průchodem seznamem
17. Postupná aplikace zvolené funkce na všechny prvky seznamu
18. Funkce vyššího řádu typu reduce
19. Repositář s demonstračními příklady
1. Řídicí konstrukce v programovacím jazyku OCaml
V osmé části seriálu o programovacím jazyku OCaml se seznámíme s většinou zbývajících řídicích konstrukcí, které v tomto jazyku nalezneme. Kromě konstrukcí let a match (částečně sem spadá i and), které již dobře známe, se jedná o řídicí konstrukci if-then-else (která je součástí výrazu!), dále o blok begin-end a taktéž o dvojici programových smyček for a while. Přitom je pro jazyky z rodiny ML příznačné, že se o těchto řídicích konstrukcích zmiňujeme až po popisu pattern matchingu i typového systému jazyka (a nikoli hned v úvodním článku). Ve skutečnosti se totiž bez if-then-else i programových smyček poměrně dobře v praxi obejdeme, protože na mnoha místech lze alternativně využít pattern matching, rekurzi a standardní funkce vyššího řádu (map, fold_left, iter atd.).
2. Rozhodovací konstrukce if-then-else
Základní rozhodovací konstrukcí v mnoha programovacích jazycích je konstrukce if-then-else (což typicky znamená, že if, then a else jsou rezervovanými klíčovými slovy). V imperativních jazycích je většinou tato konstrukce chápána jako rozvětvení běhu programu, zatímco v jazycích funkcionálních se spíše jedná o výraz s podmínkou. A právě přístup, který můžeme znát z funkcionálních jazyků, je použit i v programovacím jazyku OCaml. I zde je tedy konstrukce if-then-else výrazem, který po vyhodnocení vrátí nějakou hodnotu.
S touto konstrukcí jsme se již setkali, a to například v realizaci rekurzivní funkce append určené pro spojení dvou seznamů. Výsledkem bude nový seznam, přičemž výpočet je jednoduchý – namísto původně prázdného seznamu můžeme vrátit druhý seznam, jinak vrátíme hlavu prvního seznamu spojenou s výsledkem spojení zbytku prvního seznamu se seznamem druhým (což je rekurze):
(* Naivní implementace funkce append *) let rec append (x: 'a list) y = if x == [] then y else (List.hd x) :: (append (List.tl x) y) ;; let print_list l = print_string (String.concat " " (List.map string_of_int l)) ;; print_list (append [] [1; 2; 3]);; print_list (append [1; 2; 3] []);; print_list (append [1; 2; 3] [4; 5]);; print_list (append [] []);;
Výsledky:
print_list (append [] [1; 2; 3]) ;; 1 2 3 - : unit = () print_list (append [1; 2; 3] []) ;; 1 2 3 - : unit = () print_list (append [1; 2; 3] [4; 5]) ;; 1 2 3 4 5 - : unit = () print_list (append [] []) ;; - : unit = ()
3. Náhrada if-then-else za pattern matching
V jazycích odvozených od ML (tedy i v OCamlu a F#) se ovšem častěji namísto využití konstrukce if-then-else setkáme spíše s pattern matchingem. Algoritmus realizovaný v předchozí kapitole můžeme přepsat i do následující (idiomatičtější) podoby:
(* Implementace funkce append založená na pattern matchingu *) let rec append x y = match x with | [] -> y | head :: tail -> head :: append tail y ;; let print_list l = print_string (String.concat " " (List.map string_of_int l)) ;; print_list (append [] [1; 2; 3]);; print_list (append [1; 2; 3] []);; print_list (append [1; 2; 3] [4; 5]);; print_list (append [] []);;
Výsledky přitom budou totožné s příkladem z předchozí kapitoly:
print_list (append [] [1; 2; 3]) ;; 1 2 3 - : unit = () print_list (append [1; 2; 3] []) ;; 1 2 3 - : unit = () print_list (append [1; 2; 3] [4; 5]) ;; 1 2 3 4 5 - : unit = () print_list (append [] []) ;; - : unit = ()
4. Forma zápisu konstrukce if-then-else
Konstrukci if-then-else, což je – jak již víme – výraz, lze zapsat různými způsoby. Setkáme se například s tím, že if a else jsou na samostatných řádcích:
let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2) ;; fib 0;; fib 1;; fib 2;; fib 10;; fib 20;;
Ovšem i následující „blokový“ způsob zápisu se používá poměrně často:
let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2) ;; fib 0;; fib 1;; fib 2;; fib 10;; fib 20;;
Setkáme se naopak i se zápisem na jediném řádku:
let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2) ;; fib 0;; fib 1;; fib 2;; fib 10;; fib 20;;
I tento algoritmus je však možné zapsat elegantněji s využitím pattern matchingu:
let rec fib n = match n with 0 -> 0 | 1 -> 1 | n -> fib (n-1) + fib (n-2) ;;
Vzhledem k tomu, že funkce fib má jen jediný argument a jejím tělem je konstrukce match, lze zápis ještě více zkrátit a založit ho na klíčovém slovu function:
let rec fib = function 0 -> 0 | 1 -> 1 | n -> fib (n-1) + fib (n-2) ;; fib 0;; fib 1;; fib 2;; fib 10;; fib 20;;
Setkáme se ovšem i se vzorkem (pattern), v němž je použit zápis s „or“ a zachycením hodnoty do pomocného lokálního symbolu (zde konkrétně symbolu x):
let rec fib = function | 0 | 1 as x -> x | n -> fib (n-1) + fib (n-2) ;; fib 0;; fib 1;; fib 2;; fib 10;; fib 20;;
5. Konstrukce if-else if-else
V poměrně mnoha situacích je nutné se rozhodovat nikoli pouze na základě jednoho logického výrazu (s výsledkem true či false), ale na několika různých podmínkách. Typicky se provádí rozhodování mezi třemi možnými variantami. Příkladem může být funkce, která na základě hodnoty svého celočíselného argumentu x vrátí řetězec „positive“, „negative“ nebo „zero“. A právě v takových situacích se setkáme s použitím else if, tedy spojení větve else z první části výrazu s dalším rozhodovacím výrazem (programovací jazyk OCaml neobsahuje klíčová slova elseif ani elif):
let classify x = if x > 0 then "positive" else if x < 0 then "negative" else "zero" ;; classify (-10);; classify (-1);; classify 0;; classify 1;; classify 10;;
Pro jistotu zkontrolujeme výsledky:
classify (-10) ;; - : string = "negative" classify (-1) ;; - : string = "negative" classify 0 ;; - : string = "zero" classify 1 ;; - : string = "positive" classify 10 ;; - : string = "positive"
6. Náhrada za pattern matching s podmínkami
Pravděpodobně nebude velkým překvapením, že i rozhodovací konstrukci z předchozí kapitoly budeme moci přepsat tak, aby se využil pattern matching. Nyní již ovšem musí být ve vzorku uvedena i podmínka, což je realizováno klíčovým slovem when (naschvál se liší od klíčového slova if). První varianta přepisu používá plnou deklaraci funkce:
let classify x = match x with | x when x < 0 -> "negative" | x when x > 0 -> "positive" | x -> "zero" ;;
Idiomatičtější je však (opět) využití klíčového slova function s odstraněním názvu (jediného) argumentu funkce a tím pádem i začátku bloku match:
let classify = function | x when x < 0 -> "negative" | x when x > 0 -> "positive" | x -> "zero" ;; classify (-10);; classify (-1);; classify 0;; classify 1;; classify 10;;
Výsledky by měly být stále totožné:
classify (-10) ;; - : string = "negative" classify (-1) ;; - : string = "negative" classify 0 ;; - : string = "zero" classify 1 ;; - : string = "positive" classify 10 ;; - : string = "positive"
7. Větší množství příkazů ve větvích: blok begin-end
V případě, že je nutno ve větvi then či else realizovat větší množství příkazů, nemůžeme tyto příkazy pouze zapsat za sebe. V takovém případě by totiž překladač jazyka OCaml nedokázal rozpoznat konec takové větve. Namísto toho musíme do větve vložit blok begin-end. Jednotlivé příkazy v bloku jsou odděleny středníkem a před klíčovým slovem end je zapsán výraz, který se (po vyhodnocení) stane návratovou hodnotou celého bloku. Nesmíme totiž zapomenout na to, že if-then-else je taktéž výrazem:
begin příkaz; příkaz; výraz end
Demonstrační příklad z předchozí kapitoly si nyní upravíme takovým způsobem, že ve větvi „x je nulové“ nejprve vypíšeme na terminál zprávu (to je příkaz) a teprve poté vrátíme řetězec „zero“ (to je konstantní výraz):
let classify x = if x > 0 then "positive" else if x < 0 then "negative" else begin print_string "Zero value detected"; "zero" end ;; classify (-10);; classify (-1);; classify 0;; classify 1;; classify 10;;
Alternativně je samozřejmě možné program zapsat nepatrně odlišně a s jiným odsazením. Logika však zůstává zachována:
let classify x = if x > 0 then "positive" else if x < 0 then "negative" else begin print_string "Zero value detected"; "zero" end ;; classify (-10);; classify (-1);; classify 0;; classify 1;; classify 10;;
Výsledky (včetně explicitního tisku na terminál):
classify (-10) ;; - : string = "negative" classify (-1) ;; - : string = "negative" classify 0 ;; Zero value detected - : string = "zero" classify 1 ;; - : string = "positive" classify 10 ;; - : string = "positive"
8. Programové smyčky v jazyku OCaml
V programovacím jazyku OCaml nalezneme dva typy programových smyček. V první řadě se jedná o smyčku for, která zde existuje v „počítané“ variantě – součástí smyčky je i počitadlo, jehož hodnota se zvyšuje, popř. snižuje o jedničku. S touto programovou smyčkou se setkáme relativně často i v praxi. A druhým typem programové smyčky je smyčka typu while (tedy smyčka s podmínkou vyhodnocovanou před vstupem do smyčky). Tato smyčka má, jak uvidíme dále, poměrně velké množství nevýhod, takže se v praxi příliš často nepoužívá.
9. Počítaná smyčka typu for
Nejjednodušším a pravděpodobně i nejčastěji používaným typem programové smyčky v jazyku OCaml je počítaná smyčka typu for. V této smyčce se pracuje s počitadlem, které je – což je poněkud zvláštní – měnitelné (mutable), ovšem jen nepřímo (vlastní smyčkou). U počitadla se zadává jeho počáteční hodnota, a za klíčovým slovem to koncová hodnota. Na rozdíl od mnoha dalších programovacích jazyků dosáhne počitadlo obou krajních hodnot (počítá tedy „včetně“):
for n = 0 to 10 do print_int n; print_string "\n"; done
Povšimněte si, že počitadlo začalo na hodnotě 0 (jako v jiných jazycích) a skončilo až na hodnotě 10 (u některých dalších jazyků by to byla hodnota 9):
for n = 0 to 10 do print_int n; print_string "\n" done
Výsledky obou variant musí být totožné:
0 1 2 3 4 5 6 7 8 9 10
10. Vnořené počítané smyčky
Programové smyčky, samozřejmě i včetně smyček typu for, můžeme vnořovat tak, jak je to známé i z dalších programovacích jazyků. Pouze nesmíme zapomenout na klíčové slovo done, za nímž se ovšem musí napsat středník, pokud tělo vnější smyčky pokračuje:
for x = 0 to 10 do for y = 0 to 10 do let z = x*y in print_int z; print_string "\t"; done; print_string "\n"; done
Alternativní zápis bez středníků u posledních příkazů smyček:
for x = 0 to 10 do for y = 0 to 10 do let z = x*y in print_int z; print_string "\t" done; print_string "\n" done
Oba příklady po svém spuštění vypíšou tabulku malé násobilky:
0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 0 2 4 6 8 10 12 14 16 18 20 0 3 6 9 12 15 18 21 24 27 30 0 4 8 12 16 20 24 28 32 36 40 0 5 10 15 20 25 30 35 40 45 50 0 6 12 18 24 30 36 42 48 54 60 0 7 14 21 28 35 42 49 56 63 70 0 8 16 24 32 40 48 56 64 72 80 0 9 18 27 36 45 54 63 72 81 90 0 10 20 30 40 50 60 70 80 90 100
11. Počítání směrem dolů
V případě, že se má hodnota počitadla snižovat (o jedničku!) a nikoli zvyšovat, postačuje namísto klíčového slova to použít klíčové slovo downto. Otočenou tabulku malé násobilky tedy získáme takto:
for x = 10 downto 0 do for y = 10 downto 0 do let z = x*y in print_int z; print_string "\t"; done; print_string "\n"; done
S výsledkem:
100 90 80 70 60 50 40 30 20 10 0 90 81 72 63 54 45 36 27 18 9 0 80 72 64 56 48 40 32 24 16 8 0 70 63 56 49 42 35 28 21 14 7 0 60 54 48 42 36 30 24 18 12 6 0 50 45 40 35 30 25 20 15 10 5 0 40 36 32 28 24 20 16 12 8 4 0 30 27 24 21 18 15 12 9 6 3 0 20 18 16 14 12 10 8 6 4 2 0 10 9 8 7 6 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0
for x = 10 to 0 do for y = 10 to 0 do let z = x*y in print_int z; print_string "\t"; done; print_string "\n"; done
12. Vnořená podmínka uvnitř smyčky
Uvnitř programové smyčky (a pochopitelně i vnořené programové smyčky) samozřejmě můžeme zapsat podmínku. Smyčka není výrazem (nic nevrací – resp. vrací hodnotu typu unit), takže i podmínka se zde používá spíše ve funkci příkazu a nikoli výrazu. Ukažme si toto chování na příkladu, v němž vypíšeme ty hodnoty malé násobilky, které jsou větší než 10:
for x = 0 to 10 do for y = 0 to 10 do let z = x*y in if z > 10 then begin print_int z; print_string "\t" end done; print_string "\n"; done
Výsledek získaný po spuštění takto upraveného příkladu:
12 14 16 18 20 12 15 18 21 24 27 30 12 16 20 24 28 32 36 40 15 20 25 30 35 40 45 50 12 18 24 30 36 42 48 54 60 14 21 28 35 42 49 56 63 70 16 24 32 40 48 56 64 72 80 18 27 36 45 54 63 72 81 90 20 30 40 50 60 70 80 90 100
13. Programová smyčka typu while
V programovacím jazyku OCaml nalezneme i programovou smyčku typu while, v níž se podmínka pro ukončení smyčky testuje před každým vstupem do jejího těla. Ovšem s tímto typem smyčky se v praxi příliš často nesetkáme. Jedním z důvodů je fakt, že se ve smyčce typicky používá nějaká řídicí proměnná. A vzhledem k tomu, že standardní proměnné jsou v OCamlu neměnitelné (immutable), je nutné namísto nich použít reference. Ostatně pokusme se spustit následující program, který je založen na použití standardní neměnitelné proměnné:
let x = 0 in while x <= 10 do print_int x; print_string "\n"; x = x + 1; done ;;
Tento program sice vypadá korektně, jenže se ve skutečnosti jedná o nekonečnou smyčku! Hodnota proměnná x se nemění (a u příkazu na čtvrtém řádku se navíc vypíše varování).
14. Korektní použití smyčky while
Korektní implementace programové smyčky s řídicí proměnnou x (typu reference) vypadá následovně:
let x = ref 0 in while !x <= 10 do print_int !x; print_string "\n"; x := !x + 1; done ;;
Už ze zápisu je patrné, jak je práce s měnitelnými proměnnými nepříjemná a proč se jim programátoři používající programovací jazyk OCaml vyhýbají.
15. Iterace nad prvky seznamu
Už v úvodní kapitole jsme si řekli, že v OCamlu se programové smyčky používají spíše zřídka. Je tomu tak z toho důvodu, že si mnohdy vystačíme s rekurzí a taktéž s funkcemi (vyššího řádu) určenými pro procházení sekvenčních datových typů, tedy typicky seznamů a polí.
Příkladem je funkce List.iter, která nám umožňuje procházet všemi prvky seznamu a pro každý prvek volat předanou funkci. Pokud například budeme chtít vypsat všechny prvky seznamu na terminál, můžeme použít tento zápis:
let uzivatele = ["Adam"; "Bozena"; "Cyril"; "Dana"] in List.iter print_endline uzivatele ;;
Tento krátký prográmek po svém spuštění vypíše na standardní výstup čtyři řádky se čtyřmi jmény (a to bez použití programové smyčky):
Adam Bozena Cyril Dana
16. Operace typu zip zkombinovaná s průchodem seznamem
V mnoha programovacích jazycích se můžeme setkat s operací typu zip, která umožní zkombinovat prvky z několika sekvencí (například ze dvou seznamů). Pokud budeme chtít, aby se zkombinovaly prvky ze dvou seznamů v jazyku OCaml a aby se výsledné dvojice například vypsaly na terminál, můžeme pro tento účel použít funkci vyššího řádu List.iter2. Této funkci se předá libovolná volaná funkce (akceptující dva parametry s korektními typy!) a taktéž dva vstupní seznamy. List.iter2 zajistí průchod oběma seznamy, přičemž se pro dvojici n-tých prvků z obou seznamů zavolá specifikovaná funkce:
let print_user id user = print_int id; print_char ':'; print_string user; print_char '\n'; ;; let uzivatele = ["Adam"; "Bozena"; "Cyril"; "Dana"] in let ids = [1; 2; 3; 4] in List.iter2 print_user ids uzivatele ;;
Po spuštění tohoto programu se na terminál vypíšou ID uživatelů následovaná jejich jmény:
1:Adam 2:Bozena 3:Cyril 4:Dana
17. Postupná aplikace zvolené funkce na všechny prvky seznamu
Ve standardní knihovně programovacího jazyka OCaml nalezneme i funkci vyššího řádu typu map. Její varianta určená pro zpracování seznamů, která se jmenuje List.map, dovoluje aplikovat uživatelem zvolenou funkci postupně na všechny prvky seznamu. Výsledkem bude nový seznam, pochopitelně korektního typu (což je důležité):
let inc x = x+1 ;; let values = [1; 2; 3; 4] in List.map inc values ;;
Pokud tento příklad spustíme, získáme seznam s prvky typu int:
List.map inc values ;; - : int list = [2; 3; 4; 5]
18. Funkce vyššího řádu typu reduce
Ve standardní knihovně programovacího jazyka OCaml nechybí ani funkce vyššího řádu typu reduce. Ovšem v jazyku OCaml se namísto označení reduce používá explicitnější označení fold_left a fold_right podle toho, z jaké strany se prvky sekvence (typicky seznamu) „redukují“. Příkladem může být součet všech prvků uložených v seznamu, přičemž operace součtu je představována funkcí nazvanou +. Výchozí hodnota akumulátoru bude 0:
let values = [1; 2; 3; 4] in List.fold_left ( + ) 0 values ;;
Naopak součin všech prvků ze seznamu lze realizovat takto:
let values = [1; 2; 3; 4] in List.fold_left ( * ) 1 values ;;
19. Repositář s demonstračními příklady
Všechny výše popsané demonstrační příklady byly uloženy do repositáře dostupného na adrese https://github.com/tisnik/ocaml-examples/. V tabulce umístěné pod tímto odstavcem jsou uvedeny odkazy na tyto příklady:
20. Odkazy na Internetu
- General-Purpose, Industrial-Strength, Expressive, and Safe
https://ocaml.org/ - OCaml playground
https://ocaml.org/play - Online Ocaml Compiler IDE
https://www.jdoodle.com/compile-ocaml-online/ - Get Started – OCaml
https://www.ocaml.org/docs - Get Up and Running With OCaml
https://www.ocaml.org/docs/up-and-running - Better OCaml (Online prostředí)
https://betterocaml.ml/?version=4.14.0 - OCaml file extensions
https://blog.waleedkhan.name/ocaml-file-extensions/ - First thoughts on Rust vs OCaml
https://blog.darklang.com/first-thoughts-on-rust-vs-ocaml/ - Standard ML of New Jersey
https://www.smlnj.org/ - Programming Languages: Standard ML – 1 (a navazující videa)
https://www.youtube.com/watch?v=2sqjUWGGzTo - 6 Excellent Free Books to Learn Standard ML
https://www.linuxlinks.com/excellent-free-books-learn-standard-ml/ - SOSML: The Online Interpreter for Standard ML
https://sosml.org/ - ML (Computer program language)
https://www.barnesandnoble.com/b/books/other-programming-languages/ml-computer-program-language/_/N-29Z8q8Zvy7 - Strong Typing
https://perl.plover.com/yak/typing/notes.html - What to know before debating type systems
http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html - Types, and Why You Should Care (Youtube)
https://www.youtube.com/watch?v=0arFPIQatCU - DynamicTyping (Martin Fowler)
https://www.martinfowler.com/bliki/DynamicTyping.html - DomainSpecificLanguage (Martin Fowler)
https://www.martinfowler.com/bliki/DomainSpecificLanguage.html - Language Workbenches: The Killer-App for Domain Specific Languages?
https://www.martinfowler.com/articles/languageWorkbench.html - Effective ML (Youtube)
https://www.youtube.com/watch?v=-J8YyfrSwTk - Why OCaml (Youtube)
https://www.youtube.com/watch?v=v1CmGbOGb2I - Try OCaml
https://try.ocaml.pro/ - CSE 341: Functions and patterns
https://courses.cs.washington.edu/courses/cse341/04wi/lectures/03-ml-functions.html - Comparing Objective Caml and Standard ML
http://adam.chlipala.net/mlcomp/ - What are the key differences between Standard ML and OCaml?
https://www.quora.com/What-are-the-key-differences-between-Standard-ML-and-OCaml?share=1 - Cheat Sheets (pro OCaml)
https://www.ocaml.org/docs/cheat_sheets.html - Think OCaml: How to Think Like a (Functional) Programmer
https://www.greenteapress.com/thinkocaml/thinkocaml.pdf - The OCaml Language Cheat Sheet
https://ocamlpro.github.io/ocaml-cheat-sheets/ocaml-lang.pdf - Syllabus (FAS CS51)
https://cs51.io/college/syllabus/ - Abstraction and Design In Computation
http://book.cs51.io/ - Learn X in Y minutes Where X=Standard ML
https://learnxinyminutes.com/docs/standard-ml/ - CSE307 Online – Summer 2018: Principles of Programing Languages course
https://www3.cs.stonybrook.edu/~pfodor/courses/summer/cse307.html - CSE307 Principles of Programming Languages course: SML part 1
https://www.youtube.com/watch?v=p1n0_PsM6hw - CSE 307 – Principles of Programming Languages – SML
https://www3.cs.stonybrook.edu/~pfodor/courses/summer/CSE307/L01_SML.pdf - SML, Some Basic Examples
https://cs.fit.edu/~ryan/sml/intro.html - History of programming languages
https://devskiller.com/history-of-programming-languages/ - History of programming languages (Wikipedia)
https://en.wikipedia.org/wiki/History_of_programming_languages - Jemný úvod do rozsáhlého světa jazyků LISP a Scheme
https://www.root.cz/clanky/jemny-uvod-do-rozsahleho-sveta-jazyku-lisp-a-scheme/ - The Evolution Of Programming Languages
https://www.i-programmer.info/news/98-languages/8809-the-evolution-of-programming-languages.html - Evoluce programovacích jazyků
https://ccrma.stanford.edu/courses/250a-fall-2005/docs/ComputerLanguagesChart.png - Poly/ML Homepage
https://polyml.org/ - PolyConf 16: A brief history of F# / Rachel Reese
https://www.youtube.com/watch?v=cbDjpi727aY - Programovací jazyk Clojure 18: základní techniky optimalizace aplikací
https://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Moscow ML Language Overview
https://itu.dk/people/sestoft/mosml/mosmlref.pdf - ForLoops
http://mlton.org/ForLoops - Funkcionální dobrodružství v JavaScriptu
https://blog.kolman.cz/2015/12/funkcionalni-dobrodruzstvi-v-javascriptu.html - Recenze knihy Functional Thinking (Paradigm over syntax)
https://www.root.cz/clanky/recenze-knihy-functional-thinking-paradigm-over-syntax/ - Currying
https://sw-samuraj.cz/2011/02/currying/ - Používání funkcí v F#
https://docs.microsoft.com/cs-cz/dotnet/fsharp/tutorials/using-functions - Funkce vyššího řádu
http://naucte-se.haskell.cz/funkce-vyssiho-radu - Currying (Wikipedia)
https://en.wikipedia.org/wiki/Currying - Currying (Haskell wiki)
https://wiki.haskell.org/Currying - Haskell Curry
https://en.wikipedia.org/wiki/Haskell_Curry - Moses Schönfinkel
https://en.wikipedia.org/wiki/Moses_Sch%C3%B6nfinkel - .NET framework
https://dotnet.microsoft.com/en-us/ - F# – .NET Blog
https://devblogs.microsoft.com/dotnet/category/fsharp/ - Playground: OCaml
https://ocaml.org/play - The F# Survival Guide
https://web.archive.org/web/20110715231625/http://www.ctocorner.com/fsharp/book/default.aspx - Object-Oriented Programming — The Trillion Dollar Disaster
https://betterprogramming.pub/object-oriented-programming-the-trillion-dollar-disaster-92a4b666c7c7 - Goodbye, Object Oriented Programming
https://cscalfani.medium.com/goodbye-object-oriented-programming-a59cda4c0e53 - So You Want to be a Functional Programmer (Part 1)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-1–1f15e387e536 - So You Want to be a Functional Programmer (Part 2)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-2–7005682cec4a - So You Want to be a Functional Programmer (Part 3)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-3–1b0fd14eb1a7 - So You Want to be a Functional Programmer (Part 4)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-4–18fbe3ea9e49 - So You Want to be a Functional Programmer (Part 5)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-5-c70adc9cf56a - So You Want to be a Functional Programmer (Part 6)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-6-db502830403 - Don Syme
https://en.wikipedia.org/wiki/Don_Syme - Python to OCaml: Retrospective
http://roscidus.com/blog/blog/2014/06/06/python-to-ocaml-retrospective/ - Why does Cambridge teach OCaml as the first programming language?
https://www.youtube.com/watch?v=6APBx0WsgeQ - OCaml and 7 Things You Need To Know About It In 2021 | Functional Programming | Caml
https://www.youtube.com/watch?v=s0itOsgcf9Q - OCaml 2021 – 25 years of OCaml
https://www.youtube.com/watch?v=-u_zKPXj6mw - Introduction | OCaml Programming | Chapter 1 Video 1
https://www.youtube.com/watch?v=MUcka_SvhLw&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU - Functional Programming – What | OCaml Programming | Chapter 1 Video 2
https://www.youtube.com/watch?v=JTEwC3HihFc&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=2 - Functional Programming – Why Part 1 | OCaml Programming | Chapter 1 Video 3
https://www.youtube.com/watch?v=SKr3ItChPSI&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=3 - Functional Programming – Why Part 2 | OCaml Programming | Chapter 1 Video 4
https://www.youtube.com/watch?v=eNLm5Xbgmd0&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=4 - OCaml | OCaml Programming | Chapter 1 Video 5
https://www.youtube.com/watch?v=T-DIW1dhYzo&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=5 - Five Aspects of Learning a Programming Language | OCaml Programming | Chapter 2 Video 1
https://www.youtube.com/watch?v=A5IHFZtRfBs&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=6 - Expressions | OCaml Programming | Chapter 2 Video 2
https://www.youtube.com/watch?v=3fzrFY-2ZQ8&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=7 - If Expressions | OCaml Programming | Chapter 2 Video 3
https://www.youtube.com/watch?v=XJ6QPtlPD7s&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=8 - Let Definitions | OCaml Programming | Chapter 2 Video 4
https://www.youtube.com/watch?v=eRnG4gwOTlI&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=10 - Let Expressions | OCaml Programming | Chapter 2 Video 5
https://www.youtube.com/watch?v=ug3L97FXC6A&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=10 - Variable Expressions and Scope | OCaml Programming | Chapter 2 Video 6
https://www.youtube.com/watch?v=_TpTC6eo34M&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=11 - Scope and the Toplevel | OCaml Programming | Chapter 2 Video 7
https://www.youtube.com/watch?v=4SqMkUwakEA&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=12 - Anonymous Functions | OCaml Programming | Chapter 2 Video 8
https://www.youtube.com/watch?v=JwoIIrj0bcM&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=13 - Lambdas | OCaml Programming | Chapter 2 Video 9
https://www.youtube.com/watch?v=zHHCD7MOjmw&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=15 - Operators
https://ocaml.org/docs/operators - Operator overloading
https://en.wikipedia.org/wiki/Operator_overloading - Generalized algebraic data type
https://en.wikipedia.org/wiki/Generalized_algebraic_data_type