Obsah
1. Práce se seznamy v jazyce F#
4. Využití operátoru range při konstrukci seznamu
5. Rekurzivní definice seznamu a operátor ::
6. Spojení seznamů operátorem @
7. Původní základní funkce pro práci se seznamy
8. Nová alternativa k původním funkcím: vlastnosti (properties) seznamů
10. Idiomatický způsob zápisu rekurzivního výpočtu délky seznamu
11. Záleží na pořadí větví v bloku match?
12. Rekurzivní zápis funkce append pro spojení dvou seznamů
13. Implementace funkce append založená na pattern matchingu
14. Součet hodnot všech prvků uložených v seznamu
15. Využití tail rekurze při součtu všech prvků v seznamu
16. Test, zda jsou všechny prvky seznamu kladnými čísly
18. Repositář s demonstračními příklady
1. Práce se seznamy v jazyce F#
Ve čtvrté části seriálu o programovacím jazyce F# se budeme zabývat zdánlivě triviálním tématem. Popíšeme si totiž způsoby práce s datovým typem seznam (list). Ve skutečnosti se však v programovacích jazycích odvozených od původního jazyka ML jedná o velmi flexibilní datový typ, pro jehož zpracování (a to včetně pattern matchingu) navíc existují speciální syntaktické prvky.
Seznamy (lists) jsou vedle záznamů (record) nejdůležitějším složeným datovým typem programovacího jazyka F#. Jedná se o homogenní datový typ, což znamená, že všechny prvky seznamů musí být stejného typu, což je kontrolováno překladačem (příkladem heterogenních složených typů je právě záznam nebo n-tice).
2. Konstruktor seznamů
Pokud je zřejmé, jaké prvky mají být v seznamu uloženy, lze pro konstrukci seznamů použít následující zápis, v němž jsou prvky umístěny do hranatých závorek a pro jejich vzájemné oddělení se používá středník (nikoli čárka!). Zápis tříprvkového seznamu s prvky typu celé číslo tedy může vypadat následovně:
let x = [1; 2; 3] printf "%A" x
Seznam, který tímto zápisem vznikne, má typ int list:
val x : int list = [1; 2; 3]
Pochopitelně můžeme vytvořit i seznam s prvky jiného typu:
let x = ["foo"; "bar"; "baz"] printf "%A" x
Výsledek:
val x : string list = ["foo"; "bar"; "baz"]
Prvky seznamů mohou být i záznamy, n-tice či další seznamy. Podívejme se na příklad s n-ticemi:
let x = [(1, 2); (2, 3); (3, 4)] printf "%A" x
Překladač v tomto případě opět kontroluje typ, a to rekurzivně (tedy všechny n-tice musí mít pouze dva prvky typu celé číslo):
val x : (int * int) list = [(1, 2); (2, 3); (3, 4)]
Pokus o vytvoření heterogenního seznamu skončí s chybou detekovanou již překladačem:
let x = [1; "foo"; 3] printf "%A" x
Chybová zpráva:
All elements of a list must be of the same type as the first element, which here is 'int'. This element has type 'string'.
přičemž druhý prvek tohoto seznamu je podtržen, takže je zřejmé, na kterém místě chyba vznikla.
3. Prázdný seznam
Víme již, že speciálním případem n-tice je n-tice bez prvků (unit), která se zapisuje takto:
()
I u seznamů se jedná o speciální případ, o čemž se můžeme velmi snadno přesvědčit po konstrukci prázdného seznamu (tedy uvnitř složených závorek nejsou zapsány žádné prvky):
let x = []
Povšimněte si, jakého typu je tento seznam:
val x : 'a list = []
4. Využití operátoru range při konstrukci seznamu
Pro konstrukci seznamů lze využít i operátor range zapisovaný pomocí dvou teček. Seznam s deseti (ne devíti!) prvky 1 až 10 vytvoříme takto:
let x = [1..10] printf "%A" x
Výsledek:
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
Určit lze i krok, který se zapisuje na druhou pozici (což může být matoucí; v jiných jazycích se krok a mez přehazují):
let y = [1..2..10] printf "%A" y
Výsledkem budou v tomto případě pouze liché prvky mezi 1 a 10 (včetně):
[1; 3; 5; 7; 9]
Krok může být i záporný. Opět si to otestujme:
let x = [10..-1..0] printf "%A" x
Výsledkem nyní bude jedenáct prvků (včetně nuly):
[10; 9; 8; 7; 6; 5; 4; 3; 2; 1; 0]
A konečně kombinace záporného kroku, který se navíc liší od jedničky:
let y = [10..-2..0] printf "%A" y
Výsledek:
[10; 8; 6; 4; 2; 0]
5. Rekurzivní definice seznamu a operátor ::
Sémantika seznamů je do značné míry převzata z LISPu, ovšem syntaxe práce s nimi je do značné míry odlišná. Seznam může být v tomto kontextu definován rekurzivně:
- buď je seznam prázdný (což se zapisuje, jak již víme, prázdnými hranatými závorkami [])
- nebo má formu hlava::ocas, kde hlava je prvním prvkem seznamu a ocas tvoří zbytek prvků seznamu (opět jde o seznam). Operátor :: se nazývá cons.
To ovšem například znamená, že seznam [42] je shodný se seznamem 42::[]. To si ostatně můžeme snadno otestovat:
let x = [42] printf "%A" x let y = 42::[] printf "%A" y
Výsledky:
[42] [42]
Pokusme se podobným způsobem realizovat seznam se třemi prvky:
let x = ["foo"; "bar"; "baz"] printf "%A" x let y = "foo"::"bar"::"baz"::[] printf "%A" y
Výsledky:
[foo; bar; baz] [foo; bar; baz]
Z tohoto demonstračního příkladu si můžeme odvodit dvě vlastnosti programovacího jazyka F#:
- Operátor :: je vyhodnocován zprava doleva
- Zápis seznamu stylem [prvek1;prvek2;prvek3;…] je ve skutečnosti jen syntaktických cukrem k zápisu prvek1::prvek2::prvek3…::[]
6. Spojení seznamů operátorem @
Kromě operátoru :: využijeme při práci se seznamy další speciální operátor zapisovaný znakem @. Tento operátor slouží pro spojení dvou seznamů (stejného typu!). Podívejme se na příklad použití:
let x = [1; 2; 3] let y = [1..10] let z = x @ y printf "%A" z
Výsledkem bude tento seznam:
[1; 2; 3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
Typ spojovaných seznamů si hlídá překladač:
let x = [1; 2; 3] let y = ["foo"; "bar"; "baz"] let z = x @ y printf "%A" z
Zde pochopitelně bude nalezena chyba:
Type mismatch. Expecting a
'int list'
but given a
'string list'
The type 'int' does not match the type 'string'
7. Původní základní funkce pro práci se seznamy
V programovacím jazyku ML, z něhož jazyk F# vychází, bylo definováno několik základních funkcí určených pro práci se seznamy. Pro zajímavost si tyto funkce vypišme:
| Funkce | Stručný popis |
|---|---|
| null(x) | test na prázdný seznam |
| length(x) | délka seznamu |
| hd(x) | první prvek seznamu |
| tl(x) | ocas seznamu (bez prvního prvku) |
| nth(x) | n-tý prvek seznamu |
Následuje příklad použití funkce null a tl pro rekurzivní výpočet délky seznamu v jazyce ML (SML):
(* Naivní implementace funkce length *)
fun len(x) = if null(x) then 0
else 1 + len(tl(x));
len([1,2,3,4]);
8. Nová alternativa k původním funkcím: vlastnosti (properties) seznamů
V jazyce F# výše uvedené funkce nenalezneme. Namísto toho se totiž používají takzvané vlastnosti (properties), které se zapisují s využitím tečkové notace. Všech pět výše uvedených funkcí má svoji obdobu, i když s poněkud odlišnými jmény (používají se celá slova, mj. i proto, že o jejich doplnění se pokouší integrované vývojové prostředí):
| Vlastnost | Stručný popis |
|---|---|
| list.IsEmpty | test na prázdný seznam |
| list.Length | délka seznamu |
| list.Head | první prvek seznamu |
| list.Tail | ocas seznamu (bez prvního prvku) |
| list.Item n | n-tý prvek seznamu |
Podívejme se nyní na základní způsob použití těchto vlastností – budeme zjišťovat informace o seznamu z:
let x = [1; 2; 3] let y = [1..10] let z = x @ y printf "list: %A" z printf "empty?: %b" z.IsEmpty printf "length: %d" z.Length printf "head: %A" z.Head printf "tail: %A" z.Tail printf "item 3: %A" (z.Item 3)
Výsledky budou vypadat následovně:
list: [1; 2; 3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] empty?: false length: 13 head: 1 tail: [2; 3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] item 3: 1
Reimplementace funkce len z předchozí kapitoly může vypadat následovně:
(* Naivní implementace funkce length *)
let rec len (x:'a list) =
if x.IsEmpty then 0
else 1 + (len x.Tail)
printf "%d" (len [1;2;3;4])
9. Seznamy a pattern matching
Operátor ::, o němž jsme se zmínili v předchozích kapitolách, lze využít i při zápisu vzoru (pattern) v bloku match. To tedy znamená, že můžeme zapsat test, zda seznam obsahuje na začátku nějaký prvek, jakou hodnotu má tento prvek atd. Jedná se o velmi silný koncept, která nám umožňuje elegantní realizaci mnoha funkcí, které musí zpracovat prvky seznamu. Většina těchto funkcí zpracovává seznam sekvenčně, tedy nejdříve zpracuje jeho první prvek (hlavu) a poté rekurzivně zbytek seznamu (ocas). Některé ukázky budou uvedeny v navazujících kapitolách.
10. Idiomatický způsob zápisu rekurzivního výpočtu délky seznamu
V osmé kapitole jsme si ukázali rekurzivní zápis funkce pro výpočet délky seznamu. Tuto funkci můžeme velmi snadno přepsat do podoby, v níž se použije pattern matching. Upravený tvar může vypadat následovně a velmi přesně odpovídá teoretickému zápisu algoritmu:
(* Méně naivní implementace funkce length *)
let rec len x =
match x with
| [] -> 0
| head :: tail -> 1 + len tail
printf "%d" (len [1;2;3;4])
Povšimněte si, že ve větvi začínající vzorkem head :: tail se ve skutečnosti nikde nepracuje s hodnotou prvního prvku seznamu (head). Proto můžeme tento identifikátor nahradit za podtržítko. Výsledkem bude naprosto stejná realizace algoritmu, ovšem bez přebytečných identifikátorů:
(* Méně naivní implementace funkce length *)
let rec len x =
match x with
| [] -> 0
| _ :: tail -> 1 + len tail
printf "%d" (len [1;2;3;4])
11. Záleží na pořadí větví v bloku match?
V mnoha programovacích jazycích se používá nějaká obdoba konstrukce switch-case, v níž se nějaká hodnota postupně porovnává se vzorky v jednotlivých větvích (a většinou jsou možnosti zápisu vzorků dosti omezené). Mohlo by se tedy zdát, že i v jazyku F# musíme nejdříve otestovat, zda není zpracovávaný seznam prázdný a teprve poté řešit možnost, že seznam obsahuje hlavu (tedy skutečný prvek) a ocas (ten už může být prázdný). Ovšem ve skutečnosti tomu tak přesně není, o čemž se lze velmi snadno přesvědčit, protože i následující příklad je plně funkční, i když mu předáme (přímo či nepřímo) prázdný seznam. Nedojde tedy k pádu ani k vyhození výjimky:
(* Méně naivní implementace funkce length *)
let rec len x =
match x with
| head :: tail -> 1 + len tail
| [] -> 0
printf "%d" (len [1;2;3;4])
Naproti tomu na pořadí větví záleží – zkuste si prohodit předposlední a poslední větev a zjistit, jaké řetězce se vypíšou:
let rec foo x =
match x with
| [] -> "nil"
| [x] -> "one item"
| head :: tail -> "more items"
printf "%s" (foo [])
printf "%s" (foo [1])
printf "%s" (foo [1; 2])
12. Rekurzivní zápis funkce append pro spojení dvou seznamů
Podobně si můžeme nadefinovat funkci append, která vrací nový seznam vzniklý spojením dvou seznamů x a y. Tedy například:
append([1, 2], [3, 4, 5]) [1, 2, 3, 4, 5]
Na problém implementace této funkce můžeme použít princip postupného zjednodušování problému. Známe totiž dva invarianty:
append([],z) == z append(a :: y, z) == a :: append(y,z)
Postupně tedy budeme zkracovat první seznam až dojdeme do situace, kdy je tento seznam prázdný. Přímo z těchto podmínek je možné odvodit implementaci funkce append:
(* Naivní implementace funkce append *)
let rec append (x: 'a list) y =
if x.IsEmpty then y
else x.Head :: (append x.Tail y)
printf "%A" (append [] [1; 2; 3])
printf "%A" (append [1; 2; 3] [])
printf "%A" (append [1; 2; 3] [4; 5])
printf "%A" (append [] [])
Při zavolání:
append([1,2], [3,4,5])
dojde k postupnému vykonání fáze navíjení a odvíjení, což si můžeme naznačit graficky:
1 :: append([2], [3,4,5]) 1 :: 2 :: append([], [3,4,5]) 1 :: 2 :: [3,4,5] 1 :: [2,3,4,5] [1,2,3,4,5]
Důležitý je i typ nové funkce:
val append = fn: ∀ 'a . 'a list * 'a list → 'a list;
Tento zápis nám říká, že funkce bude akceptovat dva seznamy typu „any“ a výsledkem bude další seznam typu „any“. Typ prvků seznamů sice není explicitně určen, ovšem je zaručeno, že oba dva vstupní seznamy budou mít stejný typ prvků, jako seznam výsledný.
13. Implementace funkce append založená na pattern matchingu
V praxi se vždy při zápisu algoritmů, v nichž se vyskytuje plná podoba rozeskoku if-then-else, vyplatí popřemýšlet, zda nebude výhodnější použít pattern matching. U funkce append tomu tak skutečně je, protože její varianta s pattern matchingem je mnohem čitelnější. Je v ní patrné, jak postupně přesunujeme prvky z prvního seznamu do vznikajícího seznamu výsledného (a nakonec připojíme celý druhý seznam):
(* Implementace funkce append založená na pattern matchingu *)
let rec append x y =
match x with
| [] -> y
| head :: tail -> head :: append tail y
printf "%A" (append [] [1; 2; 3])
printf "%A" (append [1; 2; 3] [])
printf "%A" (append [1; 2; 3] [4; 5])
printf "%A" (append [] [])
14. Součet hodnot všech prvků uložených v seznamu
Mnoho operací nad seznamy je založeno na postupném zpracování prvků seznamu, konkrétně od prvku prvního (hlavy). To většinou vede k velmi podobnému zápisu algoritmů, zejména při použití pattern matchingu. Ostatně si můžeme ukázat realizaci dalšího algoritmu, tentokrát algoritmu pro součet všech prvků v seznamu. Řešení bude opět rekurzivní a vzorky použité v bloku match jsou totožné se vzorky z předchozích demonstračních příkladů, což je ovšem logické, protože opět potřebujeme vyřešit dva případy – prázdný seznam a seznam s minimálně jedním prvkem:
let rec sum x =
match x with
| [] -> 0
| head :: tail -> head + sum tail
printf "%d" (sum [])
printf "%d" (sum [1; 2; 3])
15. Využití tail rekurze při součtu všech prvků v seznamu
Přímá rekurze, která není v tail pozici a kterou jsme použili při realizaci algoritmu pro součet prvků v seznamu, není v praxi příliš efektivní. Proto se můžeme pokusit o její nahrazení variantou s tail pozicí, což opět (prakticky nutně) vede k použití akumulátoru a vnitřní pomocné funkce, která je založena na tail rekurzi a kterou voláme s předáním akumulované hodnoty. Povšimněte si, že tato funkce (sumr) má dva parametry – seznam a hodnotu akumulátoru a skutečně volá sebe samu v tail pozici (tedy výsledek volané funkce je současně i výsledkem funkce aktuálně prováděné):
let sum x =
let rec sumr x a =
match x with
| [] -> a
| head :: tail -> sumr tail (a + head)
sumr x 0
printf "%d" (sum [])
printf "%d" (sum [1; 2; 3])
16. Test, zda jsou všechny prvky seznamu kladnými čísly
V posledním demonstračním příkladu, který si dnes ukážeme, je implementován algoritmus, který zjistí, jestli seznam obsahuje pouze kladná čísla. Pro prázdný seznam byla zvolena výsledná hodnota false, ale to je diskutabilní – můžete si zde dosadit true podle způsobu použití. Povšimněte si, že zde (nově) řešíme případ seznamu s jediným prvkem. Poslední větev v bloku match je již klasická – pokud je první prvek kladný, zjistíme výsledek pro zbytek seznamu a použijeme logický součin:
let rec all_pos x =
match x with
| [] -> false
| [x] -> x > 0
| head :: tail -> head > 0 && all_pos tail
printf "%b" (all_pos [])
printf "%b" (all_pos [1; 2; 3])
printf "%b" (all_pos [-1; 2; 3])
printf "%b" (all_pos [1; 2; -3])
Alternativně můžeme použít vzorek s podmínkou zapsanou ve when. Zjistíme tak kladnost prvku v jednoprvkovém seznamu. Druhá větev (bez when) se v takovém případě nepoužije – záleží zde na pořadí jednotlivých větví:
let rec all_pos x =
match x with
| [] -> false
| [x] when x > 0 -> true
| [x] -> false
| head :: tail -> head > 0 && all_pos tail
printf "%b" (all_pos [])
printf "%b" (all_pos [1; 2; 3])
printf "%b" (all_pos [-1; 2; 3])
printf "%b" (all_pos [1; 2; -3])
To, že záleží na pořadí větví, si můžete otestovat na příkladu, v němž se můžete pokusit prohodit druhou a třetí větev:
let rec last_pos x =
match x with
| [] -> "nil"
| [x] -> "x<=0"
| [x] when x > 0 -> "x>0"
| head :: tail -> last_pos tail
printf "%s" (all_pos [])
printf "%s" (all_pos [1; 2; 3])
printf "%s" (all_pos [-1; 2; 3])
printf "%s" (all_pos [1; 2; -3])
17. Obsah navazujícího článku
V navazující části článku o programovacím jazyku F# si popíšeme způsoby práce s dalšími velmi užitečnými datovými typy. V první řadě se jedná o typ Option a typ Result, což jsou v podstatě monády (nelekněte se) použité resp. přesněji řečeno převzaté do programovacího jazyka Rust. A taktéž si popíšeme způsob práce s poli (Array).
18. 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/f-sharp-examples/. V tabulce umístěné pod tímto odstavcem jsou uvedeny odkazy na tyto příklady:
| # | Příklad | Popis příkladu | Cesta |
|---|---|---|---|
| 1 | ML/fib_recursive.ml | výpočet hodnoty z Fibonacciho posloupnosti rekurzivně | https://github.com/tisnik/f-sharp-examples/tree/master/ML/fib_recursive.ml |
| 2 | ML/fib_pattern_matching.ml | výpočet hodnoty z Fibonacciho posloupnosti založený na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/ML/fib_pattern_matching.ml |
| 3 | ML/len_pattern_matching1.ml | výpočet délky seznamu založený na pattern matchingu (první varianta) | https://github.com/tisnik/f-sharp-examples/tree/master/ML/len_pattern_matching1.ml |
| 4 | ML/len_pattern_matching2.ml | výpočet délky seznamu založený na pattern matchingu (zkrácená varianta) | https://github.com/tisnik/f-sharp-examples/tree/master/ML/len_pattern_matching2.ml |
| 5 | OCaml/fib_recursive.ml | výpočet hodnoty z Fibonacciho posloupnosti rekurzivně | https://github.com/tisnik/f-sharp-examples/tree/master/OCaml/fib_recursive.ml |
| 6 | OCaml/fib_tail_recursive.ml | výpočet hodnoty z Fibonacciho posloupnosti s využitím koncové rekurze | https://github.com/tisnik/f-sharp-examples/tree/master/OCaml/fib_tail_recursive.ml |
| 7 | OCaml/fib_pattern_matching.ml | výpočet hodnoty z Fibonacciho posloupnosti založený na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/OCaml/fib_pattern_matching.ml |
| 8 | OCaml/local_binding.ml | symbol lokální uvnitř funkce | https://github.com/tisnik/f-sharp-examples/tree/master/OCaml/local_binding.ml |
| 9 | article01/function.fs | deklarace pojmenované funkce | https://github.com/tisnik/f-sharp-examples/tree/master/article01/function.fs |
| 10 | article01/lambda.fs | deklarace anonymní funkce | https://github.com/tisnik/f-sharp-examples/tree/master/article01/lambda.fs |
| 11 | article01/local_binding1.fs | lokální symboly ve funkci | https://github.com/tisnik/f-sharp-examples/tree/master/article01/local_binding1.fs |
| 12 | article01/local_binding2.fs | lokální symboly ve funkci | https://github.com/tisnik/f-sharp-examples/tree/master/article01/local_binding2.fs |
| 13 | article01/function_type1.fs | explicitní definice návratového typu funkce (korektní) | https://github.com/tisnik/f-sharp-examples/tree/master/article01/function_type1.fs |
| 14 | article01/function_type2.fs | explicitní definice návratového typu funkce (nekorektní) | https://github.com/tisnik/f-sharp-examples/tree/master/article01/function_type2.fs |
| 15 | article02/basic_binding.fs | navázání hodnoty na symbol (deklarace proměnné) | https://github.com/tisnik/f-sharp-examples/tree/master/article02/basic_binding.fs |
| 16 | article02/print_variable.fs | tisk hodnoty proměnné | https://github.com/tisnik/f-sharp-examples/tree/master/article02/print_variable.fs |
| 17 | article02/variables_and_functions.fs | předání proměnné do funkce | https://github.com/tisnik/f-sharp-examples/tree/master/article02/variables_and_functions.fs |
| 18 | article02/redefine_symbol1.fs | pokus o redefinici symbolu | https://github.com/tisnik/f-sharp-examples/tree/master/article02/redefine_symbol1.fs |
| 19 | article02/redefine_symbol2.fs | pokus o redefinici symbolu (složitější příklad) | https://github.com/tisnik/f-sharp-examples/tree/master/article02/redefine_symbol2.fs |
| 20 | article02/equal_operator1.fs | operátor = | https://github.com/tisnik/f-sharp-examples/tree/master/article02/equal_operator1.fs |
| 21 | article02/equal_operator2.fs | operátor = | https://github.com/tisnik/f-sharp-examples/tree/master/article02/equal_operator2.fs |
| 22 | article02/immutable_variable.fs | „změna“ neměnitelné proměnné | https://github.com/tisnik/f-sharp-examples/tree/master/article02/immutable_variable.fs |
| 23 | article02/mutable_variable.fs | změna měnitelné proměnné | https://github.com/tisnik/f-sharp-examples/tree/master/article02/mutable_variable.fs |
| 24 | article02/reference1.fs | reference, příklad kompatibilní s OCamlem | https://github.com/tisnik/f-sharp-examples/tree/master/article02/reference1.fs |
| 25 | article02/reference2.fs | reference, nová syntaxe pro F# | https://github.com/tisnik/f-sharp-examples/tree/master/article02/reference2.fs |
| 26 | article02/incr1.fs | standardní funkce incr | https://github.com/tisnik/f-sharp-examples/tree/master/article02/incr1.fs |
| 27 | article02/incr2.fs | zvýšení referencované hodnoty o jedničku | https://github.com/tisnik/f-sharp-examples/tree/master/article02/incr2.fs |
| 28 | article02/shadow.fs | shadowing symbolu | https://github.com/tisnik/f-sharp-examples/tree/master/article02/shadow.fs |
| 29 | article02/tuple.fs | datový typ n-tice (tuple) | https://github.com/tisnik/f-sharp-examples/tree/master/article02/tuple.fs |
| 30 | article02/record1.fs | datový typ záznam (record), deklarace proměnné tohoto typu | https://github.com/tisnik/f-sharp-examples/tree/master/article02/record1.fs |
| 31 | article02/record2.fs | datový typ záznam (record) a typová inference při deklaraci proměnné | https://github.com/tisnik/f-sharp-examples/tree/master/article02/record2.fs |
| 32 | article02/basic_binding.fsx | demonstrační příklad basic_binding.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/basic_binding.fsx |
| 33 | article02/equal_operator1.fsx | demonstrační příklad equal_operator1.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/equal_operator1.fsx |
| 34 | article02/equal_operator2.fsx | demonstrační příklad equal_operator2.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/equal_operator2.fsx |
| 35 | article02/immutable_variable.fsx | demonstrační příklad immutable_variable.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/immutable_variable.fsx |
| 36 | article02/mutable_variable.fsx | demonstrační příklad mutable_variable.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/mutable_variable.fsx |
| 37 | article02/print_variable.fsx | demonstrační příklad print_variable.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/print_variable.fsx |
| 38 | article02/redefine_symbol1.fsx | demonstrační příklad redefine_symbol1.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/redefine_symbol1.fsx |
| 39 | article02/redefine_symbol2.fsx | demonstrační příklad redefine_symbol2.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/redefine_symbol2.fsx |
| 40 | article02/variables_and_functions.fsx | demonstrační příklad variables_and_functions.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/variables_and_functions.fsx |
| 41 | article02/incr1.fsx | demonstrační příklad incr1.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/incr1.fsx |
| 42 | article02/incr2.fsx | demonstrační příklad incr2.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/incr2.fsx |
| 43 | article02/reference1.fsx | demonstrační příklad reference1.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/reference1.fsx |
| 44 | article02/reference2.fsx | demonstrační příklad reference2.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/reference2.fsx |
| 45 | article02/ident.fsx | demonstrační příklad ident.fs přepsaný do podoby skriptu pro dotnet fsi | https://github.com/tisnik/f-sharp-examples/tree/master/article02/ident.fsx |
| 46 | article03/recursion1.fs | pokus o deklaraci funkce s přímou rekurzí založený na let | https://github.com/tisnik/f-sharp-examples/tree/master/article03/recursion1.fs |
| 47 | article03/recursion2.fs | deklarace funkce s přímou rekurzí založená na let rec | https://github.com/tisnik/f-sharp-examples/tree/master/article03/recursion2.fs |
| 48 | article03/recursion3.fs | využití tail rekurze pro výpočet členu Fibonacciho posloupnosti | https://github.com/tisnik/f-sharp-examples/tree/master/article03/recursion3.fs |
| 49 | article03/recursion4.fs | obyčejná nerekurzivní funkce definovaná přes let rec | https://github.com/tisnik/f-sharp-examples/tree/master/article03/recursion4.fs |
| 50 | article03/odd_even1.fs | nepřímá rekurze (nekorektní varianta) | https://github.com/tisnik/f-sharp-examples/tree/master/article03/odd_even1.fs |
| 51 | article03/odd_even2.fs | nepřímá rekurze (taktéž nekorektní varianta) | https://github.com/tisnik/f-sharp-examples/tree/master/article03/odd_even2.fs |
| 52 | article03/odd_even3.fs | jediný korektní zápis nepřímé rekurze | https://github.com/tisnik/f-sharp-examples/tree/master/article03/odd_even3.fs |
| 53 | article03/odd_even4.fs | nepřímá rekurze bez použití klíčového slova rec | https://github.com/tisnik/f-sharp-examples/tree/master/article03/odd_even4.fs |
| 54 | article03/pattern1.fs | výpočet Faktoriálu založený na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/article03/pattern1.fs |
| 55 | article03/pattern2.fs | výpočet Faktoriálu založený na pattern matchingu, sloučení vstupů se stejným výstupem | https://github.com/tisnik/f-sharp-examples/tree/master/article03/pattern2.fs |
| 56 | article03/pattern3.fs | kontrola neplatného vstupu | https://github.com/tisnik/f-sharp-examples/tree/master/article03/pattern3.fs |
| 57 | article03/pattern4.fs | pattern matching pro větší množství hodnot | https://github.com/tisnik/f-sharp-examples/tree/master/article03/pattern4.fs |
| 58 | article03/pattern5.fs | rekurzivní implementace Ackermannovy funkce | https://github.com/tisnik/f-sharp-examples/tree/master/article03/pattern5.fs |
| 59 | article03/pattern6.fs | kontrola neplatných vstupních hodnot pro Ackermannovu funkci | https://github.com/tisnik/f-sharp-examples/tree/master/article03/pattern6.fs |
| 60 | article03/fibonacci1.fs | výpočet Fibonacciho posloupnosti založený na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/article03/fibonacci1.fs |
| 61 | article03/fibonacci2.fs | výpočet Fibonacciho posloupnosti založený na pattern matchingu (více idiomatický zápis) | https://github.com/tisnik/f-sharp-examples/tree/master/article03/fibonacci2.fs |
| 62 | article03/first.fs | funkce vracející první prvek z dvojice založená na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/article03/first.fs |
| 63 | article03/second.fs | funkce vracející druhý prvek z dvojice založená na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/article03/second.fs |
| 64 | article03/zero_coordinate.fs | test na nulovou souřadnici/souřadnice založený na pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/article03/zero_coordinate.fs |
| 65 | article03/get_model.fs | získání prvku ze záznamu (opět založeno na pattern matchingu) | https://github.com/tisnik/f-sharp-examples/tree/master/article03/get_model.fs |
| 66 | article04/list_literal1.fs | seznam se třemi prvky typu celé číslo | https://github.com/tisnik/f-sharp-examples/tree/master/article04/list_literal1.fs |
| 67 | article04/list_literal2.fs | seznam se třemi prvky typu řetězec | https://github.com/tisnik/f-sharp-examples/tree/master/article04/list_literal2.fs |
| 68 | article04/list_literal3.fs | seznam se třemi prvky typu n-tice | https://github.com/tisnik/f-sharp-examples/tree/master/article04/list_literal3.fs |
| 69 | article04/list_literal4.fs | nekorektní pokus o vytvoření seznamu s prvky různých typů | https://github.com/tisnik/f-sharp-examples/tree/master/article04/list_literal4.fs |
| 70 | article04/empty_list.fs | konstrukce prázdného seznamu | https://github.com/tisnik/f-sharp-examples/tree/master/article04/empty_list.fs |
| 71 | article04/head_tail1.fs | složení seznamu se dvěma prvky s využitím operátoru :: | https://github.com/tisnik/f-sharp-examples/tree/master/article04/head_tail1.fs |
| 72 | article04/head_tail2.fs | složení seznamu se třemi prvky s využitím operátoru :: | https://github.com/tisnik/f-sharp-examples/tree/master/article04/head_tail2.fs |
| 73 | article04/list_properties.fs | vlastnosti (properties) seznamů | https://github.com/tisnik/f-sharp-examples/tree/master/article04/list_properties.fs |
| 74 | article04/len1.fs | naivní rekurzivní výpočet délky seznamu | https://github.com/tisnik/f-sharp-examples/tree/master/article04/len1.fs |
| 75 | article04/len2.fs | vylepšený rekurzivní výpočet délky seznamu | https://github.com/tisnik/f-sharp-examples/tree/master/article04/len2.fs |
| 76 | article04/len3.fs | vylepšený rekurzivní výpočet délky seznamu | https://github.com/tisnik/f-sharp-examples/tree/master/article04/len3.fs |
| 77 | article04/range1.fs | vytvoření sekvence numerických hodnot s využitím operátoru range | https://github.com/tisnik/f-sharp-examples/tree/master/article04/range1.fs |
| 78 | article04/range2.fs | vytvoření sekvence numerických hodnot s využitím operátoru range | https://github.com/tisnik/f-sharp-examples/tree/master/article04/range2.fs |
| 79 | article04/range3.fs | vytvoření sekvence numerických hodnot s využitím operátoru range | https://github.com/tisnik/f-sharp-examples/tree/master/article04/range3.fs |
| 80 | article04/range4.fs | vytvoření sekvence numerických hodnot s využitím operátoru range | https://github.com/tisnik/f-sharp-examples/tree/master/article04/range4.fs |
| 81 | article04/join_lists.fs | spojení dvou seznamů operátorem :: | https://github.com/tisnik/f-sharp-examples/tree/master/article04/join_lists.fs |
| 82 | article04/append1.fs | implementace spojení dvou seznamů rekurzivním výpočtem | https://github.com/tisnik/f-sharp-examples/tree/master/article04/append1.fs |
| 83 | article04/append2.fs | implementace spojení dvou seznamů rekurzivním výpočtem, použití pattern matchingu | https://github.com/tisnik/f-sharp-examples/tree/master/article04/append2.fs |
| 84 | article04/sum1.fs | součet hodnot všech prvků v seznamu (bez tail rekurze) | https://github.com/tisnik/f-sharp-examples/tree/master/article04/sum1.fs |
| 85 | article04/sum2.fs | součet hodnot všech prvků v seznamu (s využitím tail rekurze) | https://github.com/tisnik/f-sharp-examples/tree/master/article04/sum2.fs |
19. Literatura
- Get Programming with F#
https://www.manning.com/books/get-programming-with-f-sharp - F# for Scientists
https://www.amazon.com/F-Scientists-Jon-Harrop-ebook/dp/B005PS97RO - Domain Modeling Made Functional
https://fsharpforfunandprofit.com/books/ - Functional Programming with F# (na Overleaf, tedy i se zdrojovými kódy)
https://www.overleaf.com/project/5bf2cb3cd9568d5a75bfcba9 - Book of F#
https://nostarch.com/fsharp - F# Programming (Wikibook)
https://en.wikibooks.org/wiki/F_Sharp_Programming - Stylish F#: Crafting Elegant Functional Code for .NET and .NET Core
https://www.amazon.com/dp/1484239997/ - ML for the Working Programmer
https://www.cl.cam.ac.uk/~lp15/MLbook/pub-details.html - Elements of ML Programming, 2nd Edition (ML97)
http://infolab.stanford.edu/~ullman/emlp.html - A tour of Standard ML
https://saityi.github.io/sml-tour/tour/welcome - The History of Standard ML
https://smlfamily.github.io/history/SML-history.pdf - The Standard ML Basis Library
https://smlfamily.github.io/Basis/ - Programming in Standard ML
http://www.cs.cmu.edu/~rwh/isml/book.pdf - Programming in Standard ML '97: A Tutorial Introduction
http://www.lfcs.inf.ed.ac.uk/reports/97/ECS-LFCS-97–364/ - Programming in Standard ML '97: An On-line Tutorial
https://homepages.inf.ed.ac.uk/stg/NOTES/ - The OCaml system release 4.13
https://ocaml.org/releases/4.13/htmlman/index.html - Real World OCaml: Functional programming for the masses
https://dev.realworldocaml.org/ - OCaml from the Very Beginning
http://ocaml-book.com/ - OCaml from the Very Beginning: More OCaml : Algorithms, Methods & Diversions
http://ocaml-book.com/more-ocaml-algorithms-methods-diversions/ - Unix system programming in OCaml
http://ocaml.github.io/ocamlunix/ - OCaml for Scientists
https://www.ffconsultancy.com/products/ocaml_for_scientists/index.html - Using, Understanding, and Unraveling The OCaml Language
https://caml.inria.fr/pub/docs/u3-ocaml/ - Developing Applications With objective Caml
https://caml.inria.fr/pub/docs/oreilly-book/index.html - Introduction to Objective Caml
http://courses.cms.caltech.edu/cs134/cs134b/book.pdf - How to Think Like a (Functional) Programmer
https://greenteapress.com/thinkocaml/index.html
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 - 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 - 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 - Why Programmers Need Limits
https://cscalfani.medium.com/why-programmers-need-limits-3d96e1a0a6db - Signatures
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/signature-files - F# for Linux People
https://carpenoctem.dev/blog/fsharp-for-linux-people/ - Ionide project
https://ionide.io/ - FsAutoComplete
https://ionide.io/Tools/fsac.html - Interactive (.NET for Jupyter Notebook)
https://github.com/dotnet/interactive/#jupyter-and-nteract - let Bindings
https://github.com/dotnet/docs/blob/main/docs/fsharp/language-reference/functions/let-bindings.md - Lambda Expressions: The fun Keyword (F#)
https://github.com/dotnet/docs/blob/main/docs/fsharp/language-reference/functions/lambda-expressions-the-fun-keyword.md - Infographic showing code complexity vs developer experience
https://twitter.com/rossipedia/status/1580639227313676288 - OCaml for the Masses: Why the next language you learn should be functional
https://queue.acm.org/detail.cfm?id=2038036 - Try EIO
https://patricoferris.github.io/try-eio/ - Try OCaml
https://try.ocaml.pro/ - ML – funkcionální jazyk s revolučním typovým systémem
https://www.root.cz/clanky/ml-funkcionalni-jazyk-s-revolucnim-typovym-systemem/ - Funkce a typový systém programovacího jazyka ML
https://www.root.cz/clanky/funkce-a-typovy-system-programovaciho-jazyka-ml/ - Curryfikace (currying), výjimky a vlastní operátory v jazyku ML
https://www.root.cz/clanky/curryfikace-currying-vyjimky-a-vlastni-operatory-v-jazyku-ml/ - Operátor J (Wikipedia)
https://en.wikipedia.org/wiki/J_operator - Standard ML (Wikipedia)
https://en.wikipedia.org/wiki/Standard_ML - 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/ - Xavier Leroy
https://en.wikipedia.org/wiki/Xavier_Leroy - Unit type
https://en.wikipedia.org/wiki/Unit_type