Definice uživatelských datových typů v jazyku F#

14. 11. 2023
Doba čtení: 43 minut

Sdílet

 Autor: Depositphotos
Velká síla programovacího jazyka F# spočívá v principu deklarace nových datových typů. Podporován je algebraický typový systém, ale například i možnost deklarace tříd s jejich hierarchií.

Obsah

1. Definice uživatelských datových typů v jazyku F#

2. Datový typ záznam (record)

3. Typová inference při definici funkcí

4. Chování algoritmu typové inference v případě dvou struktur se shodnými prvky

5. Datový typ výčet (enum)

6. Datový typ disjunktní sjednocení (discriminated union)

7. N-tice

8. N-tice a pattern matching

9. Od n-tic k sofistikovanějším disjunktním sjednocením

10. Disjunktní sjednocení s prvky typu n-tice

11. Rekurzivní datové typy

12. Datový typ třída (class)

13. Lokální symbol v deklaraci třídy

14. Konstrukce nové instance třídy realizovaná v metodě

15. Operátory definované v rámci uživatelského datového typu

16. Dědičnost

17. Operátor upcast: přetypování na předka

18. Repositář s demonstračními příklady

19. Literatura

20. Odkazy na Internetu

1. Definice uživatelských datových typů v jazyku F#

Prozatím jsme si v seriálu o programovacích jazycích OCaml a F# do značné míry vystačili se základními datovými typy programovacího jazyka F# (resp. OCamlu). Ovšem velká síla těchto dvou programovacích jazyků spočívá v principu deklarace nových datových typů. Podporován je takzvaný algebraický typový systém (který byl v OCaml dále rozšířen), ale například i možnost deklarace tříd a specifikace jejich hierarchie (i když v F# ani v OCamlu není tak velký „tlak“ na použití tříd, a to právě díky možnostem poskytovaných ostatními datovými typy).

V mnoha demonstračních příkladech uvedených v navazujících kapitolách se navíc setkáme s tím, že operace nad různými datovými typy jsou prováděny s využitím pattern matchingu, přičemž stojí za povšimnutí, že konstrukce hodnoty určitého datového typu vypadá po syntaktické stránce prakticky stejně, jako dekonstrukce hodnoty na její prvky v bloku match. To je poměrně typický rys pattern matchingu, který byl do určité míry přejat i do dalších programovacích jazyků, které dnes pattern matching podporují.

Poznámka: opět platí, že všechny dále uvedené demonstrační příklady je možné si vyzkoušet ve webové aplikaci Try F#.

2. Datový typ záznam (record)

V mnoha oblastech se používá datový typ záznam (record). V záznamech mohou být uloženy prvky (resp. přesněji řečeno složky) libovolného typu, ovšem na rozdíl od již popsaných n-tic (tuple) jsou tyto prvky pojmenovány a lze k nim přistupovat s využitím známé tečkové notace (tečka přitom není v tomto kontextu operátor, ale znak se speciálním významem – special symbol). U záznamů je, na rozdíl od n-tic, seznamů či polí, již nutné definovat nový datový typ s explicitním určením typů jednotlivých položek.

Jak práce se seznamy vypadá v praxi? Datový typ User se třemi složkami může být definován následujícím způsobem:

type User =
    { ID: int
      Name: string
      Surname: string}

Vytvoření proměnné s hodnotou tohoto typu se zapisuje stylem, který je ukázán pod tímto odstavcem:

let pepa =
    { ID = 42
      Name = "Josef"
      Surname = "Vyskočil"}
 
 
printf "%A\n" pepa

Samozřejmě si můžeme v případě potřeby nadeklarovat i funkci (například pojmenovanou print_name), která akceptuje parametr typu záznam. V této funkci navíc budeme přistupovat ke složkám záznamu s využitím dnes již téměř univerzální „tečkové notace“:

type User =
    { ID: int
      Name: string
      Surname: string}
 
let print_name (x:User) =
    printf "%s %s" x.Name x.Surname
 
let pepa =
    { ID = 42
      Name = "Josef"
      Surname = "Vyskočil"}
 
 
print_name pepa
Poznámka: prakticky totožným způsobem bylo možné se záznamy pracovat již v původním jazyku ML, od nějž je odvozen jak jazyk OCaml, tak i programovací jazyk F#.

3. Typová inference při definici funkcí

Již několikrát jsme se v tomto seriálu setkali s tím, že programovací jazyky OCaml a F# používají sofistikovaný algoritmus pro typovou inferenci (type inference), který například dokáže doplnit typ parametrů do definované funkce, a to na základě jejího těla. Můžeme si tedy vyzkoušet upravit funkci z předchozí kapitoly. Původní tvar této funkce explicitně specifikoval typ parametrů:

let print_name (x:User) =
    printf "%s %s" x.Name x.Surname

Ovšem v tomto případě (až na výjimky zmíněné níže) můžeme funkci napsat jednodušeji a přitom bude stále silně typovaná:

let print_name x =
    printf "%s %s" x.Name x.Surname

Následující skript je korektní a plně funkční:

type User =
    { ID: int
      Name: string
      Surname: string}
 
let print_name x =
    printf "%s %s" x.Name x.Surname
 
let pepa =
    { ID = 42
      Name = "Josef"
      Surname = "Vyskočil"}
 
 
print_name pepa

4. Chování algoritmu typové inference v případě dvou struktur se shodnými prvky

Při pohledu na demonstrační příklad z předchozí kapitoly by se mohlo zdát, že algoritmus pro typovou inferenci odvozuje typ parametrů funkcí podle toho, s jakými skutečnými hodnotami jsou funkce volány. Ovšem snadno se můžeme přesvědčit, že to není (zcela) pravda. V dalším skriptu jsou deklarovány dva datové typy User a UserWithoutID, které mají položky se stejným jménem Name a Surname. Ve funkci print_name se pracuje jen s položkami Name a Surname, takže typová inference odvodí, že by se mohlo jednat o parametr typu UserWithoutID. Ovšem ve skutečnosti bude funkce volána s parametrem typu User, což vede k chybě při překladu:

type User =
    { ID: int
      Name: string
      Surname: string}
 
type UserWithoutID =
    { Name: string
      Surname: string}
 
let print_name x =
    printf "%s %s" x.Name x.Surname
 
let pepa =
    { ID = 42
      Name = "Josef"
      Surname = "Vyskočil"}
 
 
(* nefunkcni varianta *)
print_name pepa

Řešením je explicitní specifikace typu parametru funkce print_name (viz podtržená část kódu):

type User =
    { ID: int
      Name: string
      Surname: string}
 
type UserWithoutID =
    { Name: string
      Surname: string}
 
let print_name (x:User) =
    printf "%s %s" x.Name x.Surname
 
let pepa =
    { ID = 42
      Name = "Josef"
      Surname = "Vyskočil"}
 
 
(* funkcni varianta *)
print_name pepa

5. Datový typ výčet (enum)

Dalším způsobem, jak v programovacím jazyku F# definovat datový typ, je definice výčtu (enum). Je to snadné, protože pouze postačuje specifikovat názvy a hodnoty jednotlivých prvků uložených ve výčtu. Hodnoty se získají snadno – opět se použije tečková notace:

type Day = Po=1 | Ut=2 | St=3 | Ct=4 | Pa=5 | So=6 | Ne=7
 
let x = Day.St
 
printf "%A\n" x

Alternativní způsob zápisu výčtu vypadá takto (použitý je pro delší názvy či hodnoty):

type Day =
     | Po=1
     | Ut=2
     | St=3
     | Ct=4
     | Pa=5
     | So=6
     | Ne=7
let x = Day.St
printf "%A\n" x
Poznámka: samozřejmě nejsme omezeni jen na hodnoty typu celé číslo.

6. Datový typ disjunktní sjednocení (discriminated union)

Velmi důležitým datovým typem je v programovacím jazyku F# typ nazývaný disjunktní sjednocení neboli discriminated union. V té nejjednodušší podobě může být tento typ definován pouhým výčtem možností:

type Day = Po | Ut | St | Ct | Pa | So | Ne
 
let x = St
 
printf "%A\n" x

Alternativní způsob zápisu:

type Day =
     | Po
     | Ut
     | St
     | Ct
     | Pa
     | So
     | Ne
let x = St
printf "%A\n" x

Až doposud by se mohlo zdát, že se vlastně jedná o typ výčet, ovšem možnosti disjunktního sjednocení jsou mnohem větší. Již jsme se setkali s typy Option a Result:

type Option<'a> =
   | Some of 'a
   | None

a:

type Result<'T,'TError> =
    | Ok of ResultValue:'T
    | Error of ErrorValue:'TError

Další podobné konstrukce budou uvedeny v navazujících kapitolách.

Poznámka: jedná se o ukázku součtových datových typů.

7. N-tice

O tom, jak se vytváří hodnoty typu n-tice (tuple) jsme si již v tomto seriálu říkali. Postačuje napsat například:

let x = (1, 1.5, "foo", (1,2)) ;;

přičemž výsledkem bude hodnota typu:

int * float * string * (int * int)

Za povšimnutí stojí především zápis * mezi typy jednotlivých prvků, což napovídá, že na rozdíl předchozího typu se v tomto případě nejedná o součtový datový typ, ale naopak o součinový datový typ (existuje jen jedna varianta).

Konkrétní typ n-tice si samozřejmě můžeme snadno zadefinovat a může se tak jednat o určitou alternativu k záznamům. V dalším příkladu je ukázán neidiomatický způsob získání jednotlivých hodnot prvků z n-tice s využitím vnořeného bloku let:

type Rectangle = int * int
 
let print_rectange r =
    let (width, height) = r in
        printf "rect: %dx%d\n" width height
 
let r1 = (10, 20)
 
print_rectange r1
Poznámka: pro jazyk F# je typické, že při pattern matchingu je samotný vzorek (pattern) zapisován stejně jako konstruktor daného typu. Tedy pokud se konstruktor zapisuje ve tvaru (položka1, položka2) bude vzorek vypadat syntakticky stejně.

8. N-tice a pattern matching

Při čtení prvků z n-tice se mnohdy setkáme s využitím pattern matchingu, který v tomto případě může mít jen jedinou větev. Podívejme se na následující příklad, v němž z n-tice obsahující šířku a výšku obdélníku získáme obě délky v samostatných lokálních proměnných width a height:

type Rectangle = int * int
 
let print_rectange (r : Rectangle) =
    match r with
    | (width, height) -> printf "rect: %dx%d\n" width height
 
let r1 = (10, 20)
 
print_rectange r1

9. Od n-tic k sofistikovanějším disjunktním sjednocením

Mnohdy se taktéž setkáme s následujícím zápisem, který nás již připravuje na seznámení se s dalšími možnostmi zápisu disjunktního sjednocení (discriminated union) – viz další kapitoly:

type Rectangle = R of int * int
 
let print_rectange (r : Rectangle) =
    match r with
    | R(width, height) -> printf "rect: %dx%d\n" width height
 
let r1 = R(10, 20)
 
print_rectange r1

Můžeme dokonce rozlišit mezi jménem typu a jménem položky – identifikátory jsou stejné, ovšem mají odlišný význam:

type Rectangle = Rectangle of int * int
 
let print_rectange (r : Rectangle) =
    match r with
    | Rectangle(width, height) -> printf "rect: %dx%d\n" width height
 
let r1 = Rectangle(10, 20)
 
print_rectange r1
Poznámka: předchozí příklad ukazuji proto, že se s ním lze setkat, i když je dosti matoucí. I když jazyk F# tento zápis umožňuje, je vhodnější mít identifikátory s unikátními jmény, i když je každý používán v jiném kontextu (tomu se ovšem v praxi stejně nevyhneme).

10. Disjunktní sjednocení s prvky typu n-tice

Nyní se dostáváme k velmi důležitému rysu typového systému programovacího jazyka F#. Můžeme totiž vytvořit nový datový typ umožňující reprezentaci hodnoty, která sama o sobě může být různého typu. Typickým příkladem je typ nazvaný Shape, který je disjunktním sjednocením jednotlivých konkrétních typů (tvarů), například obdélníku a kružnice:

type Shape = Rectangle of int * int | Circle of int
Poznámka: povšimněte si, že Rectangle je n-tice zatímco Circle je datový typ int.

Deklarace proměnných typu Shape:

let r1 = Rectangle (10, 20)
let c = Circle 100

Přidejme si ještě funkci, která bude hodnoty typu Shape tisknout. Pro rozlišení konkrétního typu hodnoty použijeme pattern matching a (opět) si povšimněte, že zápis na levé straně šipky syntakticky přesně odpovídá deklaraci hodnoty uvedené výše:

type Shape = Rectangle of int * int | Circle of int
 
let print_shape (s : Shape) =
    match s with
    | Circle r -> printf "circle: %d\n" r
    | Rectangle (width, height) -> printf "rect: %dx%d\n" width height
 
let r1 = Rectangle (10, 20)
let c = Circle 100
 
print_shape r1
print_shape c

Navíc v tomto případě můžeme typ parametru funkce print_shape vynechat; tuto práci za nás udělá algoritmus pro odvození typů (typovou inferenci):

let print_shape s =
    match s with
    | Circle r -> printf "circle: %d\n" r
    | Rectangle (width, height) -> printf "rect: %dx%d\n" width height

V praxi se namísto zápisu:

type Shape = Rectangle of int * int | Circle of int

mnohdy setkáme s rozdělením na více řádky:

type Shape =
    | Circle of int
    | Rectangle of int * int
 
let print_shape (s : Shape) =
    match s with
    | Circle r -> printf "circle: %d\n" r
    | Rectangle (width, height) -> printf "rect: %dx%d\n" width height
 
let r1 = Rectangle (10, 20)
let c = Circle 100
 
print_shape r1
print_shape c
Poznámka: naposledy – definice typu Shape nyní vizuálně do jisté míry odpovídá zápisu bloku match nad tímtéž typem. Jedná se o další elegantní rys programovacího jazyka F#.

11. Rekurzivní a generické datové typy

Disjunktní sjednocení zkombinované s n-ticemi ve skutečnosti představuje velmi silný rys programovacího jazyka F#. Ten je navíc umocněn tím, že je možné definovat i rekurzivní datový typ, kdy jedna z položek sjednocení je typem obsahujícím samotné sjednocení. Zní to jako zcela akademický problém? Podívejme se na příklad definice datového typu, který reprezentuje výrazy (ne tak, jak jsou zapsány v kódu, ale jejich inherentní rekurzivní podobu). Nový datový typ se jmenuje expression a jedná se o disjunktní sjednocení pěti možností – čtyř podvýrazů a názvu proměnných:

type expression =
    | Plus of expression * expression        (* a + b *)
    | Minus of expression * expression       (* a - b *)
    | Times of expression * expression       (* a * b *)
    | Divide of expression * expression      (* a / b *)
    | Var of string
 
let x = Times (Var "n", Plus (Var "x", Var "y"))
 
printf "%A\n" x

Ovšem možnosti datového systému jazyka F# jdou ještě dále, protože můžeme vytvořit generický datový typ. Tentokrát se bude jednat o datový typ představující strom, což je rekurzivní struktura. Povšimněte si, že existují dva typy prvků (uzlů). Prázdný (koncový uzel) nebo uzel představovaný n-ticí obsahující levý podstrom, hodnotu uloženou v uzlu a pravý podstrom (samozřejmě, že podstromy mohou být prázdné, takže se může jednat o list stromu):

type Tree<'a> =
    | E
    | T of Tree<'a> * 'a * Tree<'a>
 
let t1 = T(E, "foo", E)
let t2 = T(T(E, "foo", E), "bar", T(E, "baz", E))
 
printf "%A\n" t1
 
printf "%A\n" t2
Poznámka: můžete si sami vyzkoušet jinou reprezentaci stromu, například takovou, aby hodnoty byly uložené jen v listech stromu (potom lze namísto prázdného uzlu použít přímo generickou hodnotu, ostatní uzly budou obsahovat pouze podstromy).

12. Datový typ třída (class)

Jazyk F# je odvozen z jazyka OCaml, kde „O“ znamená „objective“. Navíc musí F# spolupracovat s dalšími jazyky v ekosystému .NET. Z obou vlastností vyplývá, že F# vlastně musí podporovat objektově orientované programování, konkrétně OOP založené na třídách (i když samotný F# je spíše funkcionálním jazykem). Podívejme se nyní na deklaraci jednoduché třídy, jejíž instance budou mít dva atributy X a Y (rozměry v jednotlivých osách) a s konstruktorem, který akceptuje dva parametry typu int (výchozí hodnoty rozměrů):

type Rectangle(x: int, y: int) =
    member this.X = x
    member this.Y = y
 
 
(* konstrukce objektu typu Rectangle *)
let r1 = Rectangle(10, 20)
 
printf "%A\n" r1

Do deklarace třídy můžeme přidat i metody. Například se může jednat o metodu nazvanou Print, která vytiskne jak název objektu, tak i jeho atributy:

type Rectangle(x: int, y: int) =
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d\n" this.X this.Y
 
let r1 = Rectangle(10, 20)
 
r1.Print()

Zajímavé ovšem je, že v metodě Print můžeme použít i hodnotu původních parametrů konstruktoru (což je v případě neměnných hodnot to stejné, jakoby se jednalo přímo o atributy objektu). Mnohdy se tedy můžeme setkat se třídami, jejichž instance sice nesou informaci o svém stavu, ale nemají deklarovány atributy:

type Rectangle(x: int, y: int) =
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d\n" x y
 
let r1 = Rectangle(10, 20)
 
r1.Print()
Poznámka: vytvořte si více instancí třídy Rectangle pro ověření, zda je vše funkční.

13. Lokální symbol v deklaraci třídy

Již v předchozí kapitole jsme mohli vidět použití parametrů předaných konstruktoru uvnitř třídy. Programovací jazyk F# dokonce umožňuje deklaraci lokálního symbolu při konstrukci třídy; tedy hodnota navázaná na symbol bude dostupná ve vytvořeném objektu. Například si můžeme spočítat plochu obdélníka a uložit si ji do lokálního symbolu area. Hodnota je posléze použita v metodě Print:

type Rectangle(x: int, y: int) =
    let area = x * y
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d with area %d\n" x y area
 
let r1 = Rectangle(10, 20)
 
r1.Print()

Samozřejmě si opět můžeme metodu Print upravit tak, aby četla hodnoty atributů:

type Rectangle(x: int, y: int) =
    let area = x * y
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d with area %d\n" this.X this.Y area
 
let r1 = Rectangle(10, 20)
 
r1.Print()

Lokální symbol nelze, na rozdíl od atributů, číst vně definice třídy. To znamená, že následující program nebude přeložitelný kvůli podtrženým řádkům:

type Rectangle(x: int, y: int) =
    let area = x * y
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d %d\n" x y area
 
let r1 = Rectangle(10, 20)
let r2 = Rectangle(1, 2)
 
printf "%d\n" r1.X
printf "%d\n" r1.Y
printf "%d\n" r1.area
 
printf "%d\n" r2.X
printf "%d\n" r2.Y
printf "%d\n" r2.area

14. Konstrukce nové instance třídy realizovaná v metodě

Atributy objektů jsou, pokud ovšem nebudeme explicitně žádat o jiné chování, neměnitelné (immutable), což je v mnoha ohledech výhoda. Relativně často se ovšem setkáme s tím, že nějaká metoda má změnit stav objektu, tj. vlastně hodnoty jeho atributů. To lze samozřejmě zařídit tak, že se příslušné atributy deklarují takovým způsobem, aby byly měnitelné. Ovšem mnohdy je výhodnější použít odlišný přístup – taková metoda bude vracet nový objekt, ovšem již se změněným stavem. Příkladem může být požadavek na změnu velikosti obdélníka, tedy získání obdélníka, jehož rozměry na x-ové a y-ové ose budou zvětšeny nebo zmenšeny o nějaké hodnoty dx a dy. Pro tento účel lze deklarovat metodu Enlarge, která vrací novou instanci Rectangle (ale stávající instanci nijak nemění):

type Rectangle(x: int, y: int) =
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d\n" this.X this.Y
    member this.Enlarge(dx, dy) =
        Rectangle(this.X + dx, this.Y + dy)

Chování takto deklarované třídy si můžeme snadno ověřit například na tomto kódu:

let r1 = Rectangle(10, 20)
r1.Print()
 
let r2 = r1.Enlarge(1, 2)
 
r1.Print()
r2.Print()
Poznámka: obdélník r1 je vytištěn dvakrát, aby bylo patrné, jak ho zavolání metody Enlarge změnilo či naopak nezměnilo.

15. Operátory definované v rámci uživatelského datového typu

V předchozím článku jsme se seznámili s tím, jakým způsobem je v programovacím jazyku F# umožněno definovat nové operátory, popř. změnit chování existujících operátorů. Ovšem prozatím jsme se věnovali jen operátorům na globální úrovni (resp. na úrovni jednotlivých modulů, o tom však až příště). V praxi je však mnohem užitečnější definice operátoru v rámci určité třídy. Například si můžeme nadefinovat třídu reprezentující dvousložkový vektor:

type Vector(x: int, y: int) =
    member this.X = x
    member this.Y = y

Pro tuto třídu, resp. přesněji řečeno pro instance této třídy, lze přetížit standardní operátor + tak, aby skutečně prováděl součet dvou vektorů a vracel vektor nový:

static member (+) (a : Vector, b : Vector) =
    Vector(a.X + b.X, a.Y + b.Y)

Takto vypadá třída Vector s definicí přetíženého operátoru:

type Vector(x: int, y: int) =
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Vector: %dx%d\n" this.X this.Y
    static member (+) (a : Vector, b : Vector) =
        Vector(a.X + b.X, a.Y + b.Y)
 
let v1 = Vector(10, 20)
v1.Print()
 
let v2 = Vector(1, 2)
v2.Print()
 
let v3 = v1 + v2
v3.Print()
Poznámka: pochopitelně zůstaly původní vlastnosti operátoru + zachovány pro ty datové typy, pro které byl operátor navržen (celá čísla, řetězce atd.).

Typicky u přetížených operátorů, ale i u dalších malých metod, může být výhodné použít modifikátor inline, který může vést k vygenerování rychlejšího strojového kódu. Úprava předchozího demonstračního příkladu je v tomto případě snadná:

type Vector(x: int, y: int) =
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Vector: %dx%d\n" this.X this.Y
    static member inline (+) (a : Vector, b : Vector) =
        Vector(a.X + b.X, a.Y + b.Y)
 
let v1 = Vector(10, 20)
v1.Print()
 
let v2 = Vector(1, 2)
v2.Print()
 
let v3 = v1 + v2
v3.Print()

16. Dědičnost

Posledním tématem, kterému se dnes budeme alespoň ve stručnosti věnovat, je realizace dědičnosti v programovacím jazyku F#. Ukažme si její využití na jednoduchém příkladu, v němž je definována nadtřída nazvaná Shape, ze které je odvozena třída Rectangle (povšimněte si řádku začínajícího klíčovým slovem inherit):

type Shape() =
    member this.Print() = ()
 
type Rectangle(x: int, y: int) =
    inherit Shape()
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d\n" this.X this.Y
    member this.Enlarge(dx, dy) =
        Rectangle(this.X + dx, this.Y + dy)
 
let r1 = Rectangle(10, 20)
r1.Print()
 
let r2 = r1.Enlarge(1, 2)
r2.Print()
Poznámka: třída Shape není definována jako abstraktní, takže lze vytvořit její instanci. A pokud si to chcete ověřit, je lepší změnit její metodu Print:
Poznámka2: případné volání konstruktoru nadtřídy se provádí právě na řádku inherit.
type Shape() =
    member this.Print() = printf "Shapeless shape"

Samozřejmě je možné z jedné nadtřídy odvodit více podtříd, takže se vytváří klasická hierarchie tříd:

type Shape() =
    member this.Print() = ()
 
type Circle(r: int) =
    inherit Shape()
    member this.R = r
    member this.Print() =
        printf "Circle: %d\n" this.R
    member this.Enlarge(dr) =
        Circle(this.R + dr)
 
type Rectangle(x: int, y: int) =
    inherit Shape()
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d\n" this.X this.Y
    member this.Enlarge(dx, dy) =
        Rectangle(this.X + dx, this.Y + dy)
 
let r1 = Rectangle(10, 20)
r1.Print()
 
let r2 = r1.Enlarge(1, 2)
r2.Print()
 
let c1 = Circle(10)
c1.Print()
 
let c2 = c1.Enlarge(1)
c2.Print()
Poznámka: pokud pracujete s programovacím jazykem založeným na třídním OOP, asi vás napadlo, jaké nedostatky předchozí kód obsahuje. Postupně je budeme „vychytávat“.

17. Operátor upcast: přetypování na předka

V programovacím jazyku F# nalezneme mj. i dva „šipkové“ operátory, které jsme minule vynechali. Jeden z těchto operátorů se zapisuje znakem :> a provádí konverzi hodnoty na třídu, která se v hierarchii nachází výše. Z tohoto důvodu se tento operátor nazývá upcast.

Podívejme se nyní na základní způsob použití tohoto operátoru. Použijeme naši hierarchii tříd Shape:Circle a Shape:Rectangle:

type Shape() =
    member this.Print() = printf "Shapeless shape"
 
type Circle(r: int) =
    inherit Shape()
    member this.R = r
    member this.Print() =
        printf "Circle: %d\n" this.R
    member this.Enlarge(dr) =
        Circle(this.R + dr)
 
type Rectangle(x: int, y: int) =
    inherit Shape()
    member this.X = x
    member this.Y = y
    member this.Print() =
        printf "Rectangle: %dx%d\n" this.X this.Y
    member this.Enlarge(dx, dy) =
        Rectangle(this.X + dx, this.Y + dy)

Necháme si zkonstruovat několik instancí tříd Rectangle a Circle:

let r1 = Rectangle(10, 20)
r1.Print()
 
let r2 = r1.Enlarge(1, 2)
r2.Print()
 
let c1 = Circle(10)
c1.Print()
 
let c2 = c1.Enlarge(1)
c2.Print()

Další objekt bude získán z instance r1, ale bude přetypován na instanci třídy Shape:

let s1 = r1 :> Shape
s1.Print()

Výsledky ukazují, jak bude vše probíhat v runtime:

Rectangle: 10x20
Rectangle: 11x22
Circle: 10
Circle: 11
Shapeless shape

Existuje i operátor downcast zapisovaný znaky :?>. Jeho chování je v praxi poněkud složitější a proto se k němu ještě vrátíme v dalším článku:

bitcoin školení listopad 24

let s2 = s1 :?> Rectangle
s2.Print()
 
let s3 = s1 :?> Circle
s3.Print()

Tato část kódu po svém překladu a spuštění vypíše:

Rectangle: 10x20
Circle: undefined
Poznámka: jak sami vidíte, problematická je zejména druhá konverze. Konkrétně jsme z instance třídy Rectangle udělali instanci třídy Shape a posléze instanci třídy Circle, což pochopitelně bez dalších podpůrných částí kódu nemůže pracovat korektně.

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_re­cursive.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_pat­tern_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_pat­tern_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_pat­tern_matching2.ml
       
5 OCaml/fib_recursive.ml výpočet hodnoty z Fibonacciho posloupnosti rekurzivně https://github.com/tisnik/f-sharp-examples/tree/master/OCam­l/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/OCam­l/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/OCam­l/fib_pattern_matching.ml
8 OCaml/local_binding.ml symbol lokální uvnitř funkce https://github.com/tisnik/f-sharp-examples/tree/master/OCam­l/local_binding.ml
       
9 article01/function.fs deklarace pojmenované funkce https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle01/function.fs
10 article01/lambda.fs deklarace anonymní funkce https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle01/lambda.fs
11 article01/local_binding1.fs lokální symboly ve funkci https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle01/local_binding1.fs
12 article01/local_binding2.fs lokální symboly ve funkci https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle01/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/arti­cle01/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/arti­cle01/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/arti­cle02/basic_binding.fs
16 article02/print_variable.fs tisk hodnoty proměnné https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/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/arti­cle02/variables_and_functi­ons.fs
18 article02/redefine_symbol1.fs pokus o redefinici symbolu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/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/arti­cle02/redefine_symbol2.fs
       
20 article02/equal_operator1.fs operátor = https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/equal_operator1.fs
21 article02/equal_operator2.fs operátor = https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/equal_operator2.fs
       
22 article02/immutable_variable.fs „změna“ neměnitelné proměnné https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/immutable_variable.fs
23 article02/mutable_variable.fs změna měnitelné proměnné https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/mutable_variable.fs
24 article02/reference1.fs reference, příklad kompatibilní s OCamlem https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/reference1.fs
25 article02/reference2.fs reference, nová syntaxe pro F# https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/reference2.fs
26 article02/incr1.fs standardní funkce incr https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/incr1.fs
27 article02/incr2.fs zvýšení referencované hodnoty o jedničku https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/incr2.fs
28 article02/shadow.fs shadowing symbolu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/shadow.fs
       
29 article02/tuple.fs datový typ n-tice (tuple) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/variables_and_functi­ons.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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle02/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/arti­cle03/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/arti­cle03/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/arti­cle03/recursion3.fs
49 article03/recursion4.fs obyčejná nerekurzivní funkce definovaná přes let rec https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/recursion4.fs
       
50 article03/odd_even1.fs nepřímá rekurze (nekorektní varianta) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/odd_even1.fs
51 article03/odd_even2.fs nepřímá rekurze (taktéž nekorektní varianta) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/odd_even2.fs
52 article03/odd_even3.fs jediný korektní zápis nepřímé rekurze https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/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/arti­cle03/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/arti­cle03/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/arti­cle03/pattern2.fs
56 article03/pattern3.fs kontrola neplatného vstupu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/pattern3.fs
57 article03/pattern4.fs pattern matching pro větší množství hodnot https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/pattern4.fs
58 article03/pattern5.fs rekurzivní implementace Ackermannovy funkce https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/pattern5.fs
59 article03/pattern6.fs kontrola neplatných vstupních hodnot pro Ackermannovu funkci https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle03/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/arti­cle03/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/arti­cle03/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/arti­cle03/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/arti­cle03/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/arti­cle03/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/arti­cle03/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/arti­cle04/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/arti­cle04/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/arti­cle04/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/arti­cle04/list_literal4.fs
70 article04/empty_list.fs konstrukce prázdného seznamu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle04/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/arti­cle04/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/arti­cle04/head_tail2.fs
       
73 article04/list_properties.fs vlastnosti (properties) seznamů https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle04/list_properties.fs
74 article04/len1.fs naivní rekurzivní výpočet délky seznamu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle04/len1.fs
75 article04/len2.fs vylepšený rekurzivní výpočet délky seznamu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle04/len2.fs
76 article04/len3.fs vylepšený rekurzivní výpočet délky seznamu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle04/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/arti­cle04/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/arti­cle04/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/arti­cle04/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/arti­cle04/range4.fs
       
81 article04/join_lists.fs spojení dvou seznamů operátorem :: https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle04/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/arti­cle04/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/arti­cle04/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/arti­cle04/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/arti­cle04/sum2.fs
       
86 article05/option_type.fs definice datového typu Option https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/option_type.fs
87 article05/none_value.fs hodnota None https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/none_value.fs
88 article05/some_value1.fs hodnota Some(typ) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/some_value1.fs
89 article05/some_value2.fs hodnota Some(typ) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/some_value2.fs
90 article05/option_value.fs přístup k zapouzdřené hodnotě přes Option.Value https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/option_value.fs
91 article05/is_none_is_some1.fs detekce, zda je hodnota Option rovna None či Some https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/is_none_is_some1.fs
92 article05/is_none_is_some2.fs detekce, zda je hodnota Option rovna None či Some https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/is_none_is_some2.fs
93 article05/option_exists1.fs základní pattern matching, korektní varianta https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/option_exists1.fs
94 article05/option_exists2.fs základní pattern matching, nekorektní varianta https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/option_exists2.fs
95 article05/option_exists3.fs základní pattern matching, nekorektní varianta https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/option_exists3.fs
96 article05/find_in_list1.fs vyhledávání prvku v seznamu založené na pattern matchingu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/find_in_list1.fs
97 article05/find_in_list2.fs varianta předchozího programu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/find_in_list2.fs
       
98 article05/result_type.fs definice datového typu Result https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/result_type.fs
99 article05/result_divide1.fs ukázka použití datového typu Result https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/result_divide1.fs
100 article05/result_divide2.fs ukázka použití datového typu Result a pattern matchingu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/result_divide2.fs
101 article05/result_divide3.fs stejné jako result_divide1.fs, ovšem bez explicitního zápisu typů https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/result_divide3.fs
102 article05/result_divide4.fs stejné jako result_divide2.fs, ovšem bez explicitního zápisu typů https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/result_divide4.fs
       
103 article05/array_value.fs deklarace pole výčtem jeho prvků https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_value.fs
104 article05/array_create.fs funkce Array.create pro konstrukci pole https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_create.fs
105 article05/array_init1.fs inicializace prvků pole funkcí Array.init https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_init1.fs
106 article05/array_init2.fs inicializace prvků pole funkcí Array.init https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_init2.fs
107 article05/array_indexing.fs indexování prvků pole https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_indexing.fs
108 article05/array_mutation.fs mutace pole: modifikace hodnot jeho prvků https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_mutation.fs
109 article05/array_zerocreate.fs konstrukce pole s nulovými prvky https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle05/array_zerocreate.fs
       
110 article06/unary_ops1.fs unární aritmetické operátory a datový typ int https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/unary_ops1.fs
111 article06/unary_ops2.fs unární aritmetické operátory a datový typ float https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/unary_ops2.fs
112 article06/binary_ops.fs binární aritmetické operátory a datový typ int https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/binary_ops.fs
113 article06/boolean.fs Booleovské unární i binární operátory https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/boolean.fs
114 article06/relational1.fs relační operátory, porovnání hodnot typu int https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/relational1.fs
115 article06/relational2.fs relační operátory, porovnání hodnot typu string https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/relational2.fs
116 article06/relational3.fs relační operátory, porovnání hodnot typu array https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/relational3.fs
117 article06/relational4.fs relační operátory, porovnání hodnot typu array https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/relational4.fs
118 article06/bit_operators.fs operátory provádějící operaci bit po bitu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/bit_operators.fs
119 article06/shifts.fs operátory pro bitové a aritmetické posuny https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/shifts.fs
       
120 article06/func_pipeline1.fs kolona funkcí vytvořená operátorem |> https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_pipeline1.fs
121 article06/func_pipeline2.fs kolona funkcí vytvořená operátorem <| https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_pipeline2.fs
122 article06/func_pipeline3.fs kolona funkcí vytvořená operátorem ||> https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_pipeline3.fs
123 article06/func_pipeline4.fs kolona funkcí vytvořená operátorem ||> https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_pipeline4.fs
124 article06/func_pipeline5.fs kolona funkcí vytvořená operátorem |||> https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_pipeline5.fs
       
125 article06/func_composition1.fs kompozice dvou funkcí operátorem >> https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_composition1.fs
126 article06/func_composition2.fs kompozice dvou funkcí operátorem << https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_composition2.fs
127 article06/func_composition3.fs kompozice tří funkcí operátorem >> https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/func_composition3.fs
       
128 article06/new_operator1.fs definice nového binárního operátoru https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/new_operator1.fs
129 article06/new_operator2.fs přepis stávajícího binárního operátoru https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/new_operator2.fs
130 article06/new_operator3.fs rozlišení unárního a binárního operátoru https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/new_operator3.fs
131 article06/new_operator4.fs rozlišení unárního a binárního operátoru https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/new_operator4.fs
132 article06/new_operator5.fs otestování asociativity operátoru https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle06/new_operator5.fs
       
133 article07/circle_rectangle1.fs datový typ přestavující buď kružnici nebo obdélník https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/circle_rectangle1.fs
134 article07/circle_rectangle2.fs datový typ přestavující buď kružnici nebo obdélník https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/circle_rectangle2.fs
135 article07/discriminated_union.fs použití datového typu discriminated union https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/discriminated_union­.fs
136 article07/enum1.fs příklad použití datového typu výčet https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/enum.fs
137 article07/enum2.fs příklad použití datového typu výčet https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/enum.fs
       
138 article07/rectangle1.fs typ Rectangle založený na n-tici https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/rectangle1.fs
139 article07/rectangle2.fs úprava předchozího příkladu; pattern matching https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/rectangle2.fs
140 article07/rectangle3.fs úprava předchozího příkladu, explicitní pojmenování https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/rectangle3.fs
141 article07/rectangle4.fs různé jmenné prostory https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/rectangle4.fs
       
142 article07/struct_type1.fs definice záznamu (record, struct) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/struct_type1.fs
143 article07/struct_type2.fs rozšíření o funkci pro tisk záznamu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/struct_type2.fs
144 article07/struct_type3.fs automatické odvození datového typu parametru funkce https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/struct_type3.fs
145 article07/struct_type4.fs otestování mezí automatického odvozování typů parametrů (nefunkční varianta) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/struct_type4.fs
146 article07/struct_type5.fs otestování mezí automatického odvozování typů parametrů (funkční varianta) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/struct_type5.fs
147 article07/tree.fs datový typ představující rekurzivní definici binárního stromu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/tree.fs
       
148 article07/object1.fs jednoduchá třída s dvojicí atributů https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object1.fs
149 article07/object2.fs přidání metody do třídy https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object2.fs
150 article07/object3.fs třída s lokální vazbou na symbol (binding) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object3.fs
151 article07/object4.fs dtto, ale s explicitním přístupem k atributům objektu https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object4.fs
152 article07/object5.fs metoda vytvářející nový objekt https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object5.fs
153 article07/object6.fs třída reprezentující dvouprvkový vektor https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object6.fs
154 article07/object7.fs doplnění předchozí třídy o přetížený operátor + https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/object7.fs
       
155 article07/oop1.fs objektově orientované programování: vztah mezi dvojicí tříd (předek, potomek) https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/oop1.fs
156 article07/oop2.fs objektově orientované programování: dvojice tříd odvozená ze stejného předka https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/oop2.fs
157 article07/oop3.fs objektově orientované programování: přetypování na předka https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/oop3.fs
       
158 article07/local_symbol1.fs čtení atributů objektu mimo definici třídy https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/local_symbol1.fs
159 article07/local_symbol2.fs čtení lokálních symbolů objektu mimo definici třídy https://github.com/tisnik/f-sharp-examples/tree/master/arti­cle07/local_symbol2.fs

19. Literatura

Poznámka: v této kapitole jsou uvedeny knihy o jazyku ML, resp. Standard ML i knihy o programovacím jazyku OCaml, který ze Standard ML ze značné míry vychází. A samozřejmě nezapomeneme ani na knihy o jazyku F#:
  1. Get Programming with F#
    https://www.manning.com/books/get-programming-with-f-sharp
  2. F# for Scientists
    https://www.amazon.com/F-Scientists-Jon-Harrop-ebook/dp/B005PS97RO
  3. Domain Modeling Made Functional
    https://fsharpforfunandpro­fit.com/books/
  4. Functional Programming with F# (na Overleaf, tedy i se zdrojovými kódy)
    https://www.overleaf.com/pro­ject/5bf2cb3cd9568d5a75bfcb­a9
  5. Book of F#
    https://nostarch.com/fsharp
  6. F# Programming (Wikibook)
    https://en.wikibooks.org/wi­ki/F_Sharp_Programming
  7. Stylish F#: Crafting Elegant Functional Code for .NET and .NET Core
    https://www.amazon.com/dp/1484239997/
  8. ML for the Working Programmer
    https://www.cl.cam.ac.uk/~lp15/MLbo­ok/pub-details.html
  9. Elements of ML Programming, 2nd Edition (ML97)
    http://infolab.stanford.e­du/~ullman/emlp.html
  10. A tour of Standard ML
    https://saityi.github.io/sml-tour/tour/welcome
  11. The History of Standard ML
    https://smlfamily.github.i­o/history/SML-history.pdf
  12. The Standard ML Basis Library
    https://smlfamily.github.io/Basis/
  13. Programming in Standard ML
    http://www.cs.cmu.edu/~rwh/is­ml/book.pdf
  14. Programming in Standard ML '97: A Tutorial Introduction
    http://www.lfcs.inf.ed.ac­.uk/reports/97/ECS-LFCS-97–364/
  15. Programming in Standard ML '97: An On-line Tutorial
    https://homepages.inf.ed.ac­.uk/stg/NOTES/
  16. The OCaml system release 4.13
    https://ocaml.org/releases/4­.13/htmlman/index.html
  17. Real World OCaml: Functional programming for the masses
    https://dev.realworldocaml.org/
  18. OCaml from the Very Beginning
    http://ocaml-book.com/
  19. OCaml from the Very Beginning: More OCaml : Algorithms, Methods & Diversions
    http://ocaml-book.com/more-ocaml-algorithms-methods-diversions/
  20. Unix system programming in OCaml
    http://ocaml.github.io/ocamlunix/
  21. OCaml for Scientists
    https://www.ffconsultancy­.com/products/ocaml_for_sci­entists/index.html
  22. Using, Understanding, and Unraveling The OCaml Language
    https://caml.inria.fr/pub/docs/u3-ocaml/
  23. Developing Applications With objective Caml
    https://caml.inria.fr/pub/docs/oreilly-book/index.html
  24. Introduction to Objective Caml
    http://courses.cms.caltech­.edu/cs134/cs134b/book.pdf
  25. How to Think Like a (Functional) Programmer
    https://greenteapress.com/thin­kocaml/index.html

20. Odkazy na Internetu

  1. General-Purpose, Industrial-Strength, Expressive, and Safe
    https://ocaml.org/
  2. OCaml playground
    https://ocaml.org/play
  3. Online Ocaml Compiler IDE
    https://www.jdoodle.com/compile-ocaml-online/
  4. Get Started – OCaml
    https://www.ocaml.org/docs
  5. Get Up and Running With OCaml
    https://www.ocaml.org/docs/up-and-running
  6. Better OCaml (Online prostředí)
    https://betterocaml.ml/?ver­sion=4.14.0
  7. OCaml file extensions
    https://blog.waleedkhan.name/ocaml-file-extensions/
  8. First thoughts on Rust vs OCaml
    https://blog.darklang.com/first-thoughts-on-rust-vs-ocaml/
  9. Standard ML of New Jersey
    https://www.smlnj.org/
  10. Programming Languages: Standard ML – 1 (a navazující videa)
    https://www.youtube.com/wat­ch?v=2sqjUWGGzTo
  11. 6 Excellent Free Books to Learn Standard ML
    https://www.linuxlinks.com/excellent-free-books-learn-standard-ml/
  12. SOSML: The Online Interpreter for Standard ML
    https://sosml.org/
  13. ML (Computer program language)
    https://www.barnesandnoble­.com/b/books/other-programming-languages/ml-computer-program-language/_/N-29Z8q8Zvy7
  14. Strong Typing
    https://perl.plover.com/y­ak/typing/notes.html
  15. What to know before debating type systems
    http://blogs.perl.org/user­s/ovid/2010/08/what-to-know-before-debating-type-systems.html
  16. Types, and Why You Should Care (Youtube)
    https://www.youtube.com/wat­ch?v=0arFPIQatCU
  17. DynamicTyping (Martin Fowler)
    https://www.martinfowler.com/bli­ki/DynamicTyping.html
  18. DomainSpecificLanguage (Martin Fowler)
    https://www.martinfowler.com/bli­ki/DomainSpecificLanguage­.html
  19. Language Workbenches: The Killer-App for Domain Specific Languages?
    https://www.martinfowler.com/ar­ticles/languageWorkbench.html
  20. Effective ML (Youtube)
    https://www.youtube.com/watch?v=-J8YyfrSwTk
  21. Why OCaml (Youtube)
    https://www.youtube.com/wat­ch?v=v1CmGbOGb2I
  22. CSE 341: Functions and patterns
    https://courses.cs.washin­gton.edu/courses/cse341/04wi/lec­tures/03-ml-functions.html
  23. Comparing Objective Caml and Standard ML
    http://adam.chlipala.net/mlcomp/
  24. 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
  25. Cheat Sheets (pro OCaml)
    https://www.ocaml.org/doc­s/cheat_sheets.html
  26. Syllabus (FAS CS51)
    https://cs51.io/college/syllabus/
  27. Abstraction and Design In Computation
    http://book.cs51.io/
  28. Learn X in Y minutes Where X=Standard ML
    https://learnxinyminutes.com/doc­s/standard-ml/
  29. CSE307 Online – Summer 2018: Principles of Programing Languages course
    https://www3.cs.stonybrook­.edu/~pfodor/courses/summer/cse307­.html
  30. CSE307 Principles of Programming Languages course: SML part 1
    https://www.youtube.com/wat­ch?v=p1n0_PsM6hw
  31. CSE 307 – Principles of Programming Languages – SML
    https://www3.cs.stonybrook­.edu/~pfodor/courses/summer/CSE307/L01_SML­.pdf
  32. SML, Some Basic Examples
    https://cs.fit.edu/~ryan/sml/in­tro.html
  33. History of programming languages
    https://devskiller.com/history-of-programming-languages/
  34. History of programming languages (Wikipedia)
    https://en.wikipedia.org/wi­ki/History_of_programming_lan­guages
  35. 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/
  36. The Evolution Of Programming Languages
    https://www.i-programmer.info/news/98-languages/8809-the-evolution-of-programming-languages.html
  37. Evoluce programovacích jazyků
    https://ccrma.stanford.edu/cou­rses/250a-fall-2005/docs/ComputerLanguagesChart.png
  38. Poly/ML Homepage
    https://polyml.org/
  39. PolyConf 16: A brief history of F# / Rachel Reese
    https://www.youtube.com/wat­ch?v=cbDjpi727aY
  40. Programovací jazyk Clojure 18: základní techniky optimalizace aplikací
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  41. Moscow ML Language Overview
    https://itu.dk/people/ses­toft/mosml/mosmlref.pdf
  42. ForLoops
    http://mlton.org/ForLoops
  43. Funkcionální dobrodružství v JavaScriptu
    https://blog.kolman.cz/2015/12/fun­kcionalni-dobrodruzstvi-v-javascriptu.html
  44. Recenze knihy Functional Thinking (Paradigm over syntax)
    https://www.root.cz/clanky/recenze-knihy-functional-thinking-paradigm-over-syntax/
  45. Currying
    https://sw-samuraj.cz/2011/02/currying/
  46. Používání funkcí v F#
    https://docs.microsoft.com/cs-cz/dotnet/fsharp/tutorials/using-functions
  47. Funkce vyššího řádu
    http://naucte-se.haskell.cz/funkce-vyssiho-radu
  48. Currying (Wikipedia)
    https://en.wikipedia.org/wi­ki/Currying
  49. Currying (Haskell wiki)
    https://wiki.haskell.org/Currying
  50. Haskell Curry
    https://en.wikipedia.org/wi­ki/Haskell_Curry
  51. Moses Schönfinkel
    https://en.wikipedia.org/wi­ki/Moses_Sch%C3%B6nfinkel
  52. .NET framework
    https://dotnet.microsoft.com/en-us/
  53. F# – .NET Blog
    https://devblogs.microsof­t.com/dotnet/category/fshar­p/
  54. Playground: OCaml
    https://ocaml.org/play
  55. The F# Survival Guide
    https://web.archive.org/web/20110715231625/htt­p://www.ctocorner.com/fshar­p/book/default.aspx
  56. Object-Oriented Programming — The Trillion Dollar Disaster
    https://betterprogramming.pub/object-oriented-programming-the-trillion-dollar-disaster-92a4b666c7c7
  57. Goodbye, Object Oriented Programming
    https://cscalfani.medium.com/goodbye-object-oriented-programming-a59cda4c0e53
  58. 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
  59. 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
  60. 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
  61. 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
  62. 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
  63. 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
  64. Don Syme
    https://en.wikipedia.org/wi­ki/Don_Syme
  65. Python to OCaml: Retrospective
    http://roscidus.com/blog/blog/2014/06/0­6/python-to-ocaml-retrospective/
  66. Why Programmers Need Limits
    https://cscalfani.medium.com/why-programmers-need-limits-3d96e1a0a6db
  67. Signatures
    https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/signature-files
  68. F# for Linux People
    https://carpenoctem.dev/blog/fsharp-for-linux-people/
  69. Ionide project
    https://ionide.io/
  70. FsAutoComplete
    https://ionide.io/Tools/fsac.html
  71. Interactive (.NET for Jupyter Notebook)
    https://github.com/dotnet/in­teractive/#jupyter-and-nteract
  72. let Bindings
    https://github.com/dotnet/doc­s/blob/main/docs/fsharp/lan­guage-reference/functions/let-bindings.md
  73. Lambda Expressions: The fun Keyword (F#)
    https://github.com/dotnet/doc­s/blob/main/docs/fsharp/lan­guage-reference/functions/lambda-expressions-the-fun-keyword.md
  74. Infographic showing code complexity vs developer experience
    https://twitter.com/rossi­pedia/status/1580639227313676288
  75. OCaml for the Masses: Why the next language you learn should be functional
    https://queue.acm.org/deta­il.cfm?id=2038036
  76. Try EIO
    https://patricoferris.github.io/try-eio/
  77. Try OCaml
    https://try.ocaml.pro/
  78. ML – funkcionální jazyk s revolučním typovým systémem
    https://www.root.cz/clanky/ml-funkcionalni-jazyk-s-revolucnim-typovym-systemem/
  79. Funkce a typový systém programovacího jazyka ML
    https://www.root.cz/clanky/funkce-a-typovy-system-programovaciho-jazyka-ml/
  80. 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/
  81. Operátor J (Wikipedia)
    https://en.wikipedia.org/wi­ki/J_operator
  82. Standard ML (Wikipedia)
    https://en.wikipedia.org/wi­ki/Standard_ML
  83. Xavier Leroy
    https://en.wikipedia.org/wi­ki/Xavier_Leroy
  84. Unit type
    https://en.wikipedia.org/wi­ki/Unit_type
  85. The Option type
    https://fsharpforfunandpro­fit.com/posts/the-option-type/
  86. Operators
    https://ocaml.org/docs/operators
  87. Operator overloading
    https://en.wikipedia.org/wi­ki/Operator_overloading
Seriál: F# a OCaml

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.