Definice uživatelských datových typů v jazyku OCaml

16. 11. 2023
Doba čtení: 37 minut

Sdílet

Autor: Depositphotos
Popíšeme si, jakým způsobem lze uživatelské datové typy definovat v programovacím jazyku OCaml. Uvidíme, že mezi oběma jazyky existují v této oblasti rozdíly, většinou však jen syntaktické.

Obsah

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

2. Datový typ záznam (record)

3. Funkce akceptující parametr typu záznam

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

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

6. Datový typ n-tice (tuple)

7. N-tice a pattern matching

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

9. Rekurzivní datová struktura: výraz

10. Rekurzivní generická datová struktura: strom

11. Třídy a objekty v ML jazycích

12. Deklarace třídy

13. Metoda deklarovaná ve třídě

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

15. Přetížení operátoru pro instance třídy

16. Deklarace přetíženého operátoru a automatické odvození typů operandů

17. Kam dál? GADT

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

19. Odkazy na Internetu

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

Na tento týden vydaný článek o definicích uživatelských datových typů v jazyku F# dnes navážeme, protože si řekneme, jakým způsobem lze uživatelské datové typy definovat v programovacím jazyku OCaml. Uvidíme, že mezi oběma jazyky existují v této oblasti rozdíly, většinou však jen syntaktické (ovšem prozatím jsme se nevěnovali GADT, kde jsou již rozdíly dosti velké). Pro možnost rychlého vizuálního srovnání společných vlastností a rozdílů v syntaxi dnes zkusíme novinku – všechny příklady budou zapsány jak v jazyce OCaml, tak i v jazyce F# a budou zobrazeny vedle sebe, přičemž odpovídající si řádky budou skutečně zobrazeny na společném řádku (samozřejmě jen tam, kde je to možné – tedy až na poslední dva příklady).

Původní zdrojové kódy všech demonstračních příkladů tak nebude možné vykopírovat přímo z textu článku, ovšem samozřejmě jsou k dispozici zdrojové kódy všech příkladů uvedené v osmnácté kapitole.

2. Datový typ záznam (record)

Datový typ záznam (record), jenž byl z pohledu programovacího jazyka F# popsán zde, lze samozřejmě použít i v OCamlu. Mezi oběma jazyky však v této oblasti existují určité syntaktické rozdíly. Například v OCamlu jsou prvky popsány malými písmeny a jako oddělovače mezi prvky se jak v definici typu záznam, tak i při deklaraci hodnoty používají středníky. Rozdíly jsou dobře patrné při porovnání zdrojového kódu v OCamlu a F# (zobrazeno vedle sebe):

(* OCaml *)                    (* F# *)
 
type user = {                  type User =
  id: int;                         { ID: int
  name: string;                      Name: string
  surname: string;                   Surname: string}
} ;;
  
let pepa = {                   let pepa =
  id = 42;                         { ID = 42
  name = "Josef";                    Name = "Josef"
  surname = "Vyskočil"}              Surname = "Vyskočil"}
;;
 
 
pepa;;                         printf "%A\n" pepa

3. Funkce akceptující parametr typu záznam

Samozřejmě nám nic nebrání ve vytvoření funkce, která jako svůj parametr (či parametry) akceptuje hodnotu typu záznam, což je téma, kterému jsme se věnovali v této kapitole. Opět se podívejme na (nepatrné – syntaktické) rozdíly mezi jazyky OCaml a F# při definici a volání takové funkce:

(* OCaml *)                                   (* F# *)
 
type user = {                                 type User =
  id: int;                                        { ID: int
  name: string;                                     Name: string
  surname: string;                                  Surname: string
} ;;                                          }
 
let print_user (u:user) =                     let print_user (x:User) =
  Printf.printf "%s %s\n" u.name u.surname        printf "%s %s" x.Name x.Surname
;;

let pepa = {
  id = 42;                                    let pepa =
  name = "Josef";                                 { ID = 42
  surname = "Vyskočil"}                             Name = "Josef"
;;                                              Surname = "Vyskočil"}
 
 
print_user pepa;;                             print_user pepa

Oba programovací jazyky OCaml i F# používají velmi (podobně koncipovaný) 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 (nikoli na základě parametrů použitých při jejím volání). Opět se pouze podívejme na syntaktické rozdíly mezi oběma jazyky, protože z pohledu sémantiky jsme se tomuto tématu již věnovali:

(* OCaml *)                                   (* F# *)
 
type user = {                                 type User =
  id: int;                                        { ID: int
  name: string;                                     Name: string
  surname: string;                                  Surname: string
} ;;                                          }
 
let print_user u =                            let print_user x =
  Printf.printf "%s %s\n" u.name u.surname        printf "%s %s" x.Name x.Surname
;;
 
let pepa = {                                  let pepa =
  id = 42;                                        { ID = 42
  name = "Josef";                                   Name = "Josef"
  surname = "Vyskočil"}                         Surname = "Vyskočil"}
;;
 
 
print_user pepa;;                             print_user pepa

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

Ve čtvrté kapitole předchozího článku jsme si ukázali některá úskalí algoritmu typové inference. Ten jsme totiž „zmátli“ tím, že se ve funkci print_user 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. V programovacím jazyku OCaml dojde k naprosto stejné situaci (až – opět – na poněkud odlišnou syntaxi):

(* OCaml *)                                   (* F# *)
 
type user = {                                 type User =
  id: int;                                        { ID: int
  name: string;                                     Name: string
  surname: string;                                  Surname: string
} ;;                                          }
 
type user_without_id = {                      type UserWithoutID =
  name: string;                                   { Name: string
  surname: string;                                  Surname: string
} ;;
 
let print_user u =                            let print_user x =
  Printf.printf "%s %s\n" u.name u.surname        printf "%s %s" x.Name x.Surname
;;
 
let pepa =  {                                 let pepa =
  id = 42;                                        { ID = 42
  name = "Josef";                                   Name = "Josef"
  surname = "Vyskočil"}                         Surname = "Vyskočil"}
;;
 
 
(* nefunkcni varianta *)                      (* nefunkcni varianta *)
print_user pepa;;                             print_user pepa

Řešením je explicitní specifikace typu parametru funkce print_user. Po této úpravě je již možné oba zdrojové kódy přeložit a spustit:

(* OCaml *)                                   (* F# *)
 
type user = {                                 type User =
  id: int;                                        { ID: int
  name: string;                                     Name: string
  surname: string;                                  Surname: string
} ;;                                          }
 
type user_without_id = {                      type UserWithoutID =
  name: string;                                   { Name: string
  surname: string;                                  Surname: string
} ;;                                          }
 
let print_user (u:user) =                     let print_user (x:User) =
  Printf.printf "%s %s\n" u.name u.surname        printf "%s %s" x.Name x.Surname
;;
 
let pepa =  {                                 let pepa =
  id = 42;                                        { ID = 42
  name = "Josef";                                   Name = "Josef"
  surname = "Vyskočil"}                         Surname = "Vyskočil"}
;;
 
 
(* funkcni varianta *)                        (* funkcni varianta *)
print_user pepa;;                             print_user pepa

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

Připomeňme si, že v programovacím jazyku F# existuje datový typ výčet, v němž můžeme definovat jak prvky ve výčtu, tak i jejich hodnoty. V praxi je použití tohoto typu 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, tedy podobně, jako je tomu u výše uvedených záznamů:

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

Zápis je možné provést i odlišným způsobem (který je sice delší, zato přehlednější):

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

Tento datový typ v přesné podobě v OCamlu sice nenajdeme, ovšem kromě toho existuje i typ disjunktní sjednocení (discriminated union). V té nejjednodušší podobě může být tento typ definován pouhým výčtem možností a zde již v OCamlu najdeme stejný typ:

(* OCaml *)                                      (* F# *)
 
type day = Po | Ut | St | Ct | Pa | So | Ne;;    type Day = Po | Ut | St | Ct | Pa | So | Ne
 
let x = St;;                                     let x = St
 
x;;                                              printf "%A\n" x

Popř.:

(* OCaml *)           (* F# *)
 
type day =            type Day =
    | Po                   | Po
    | Ut                   | Ut
    | St                   | St
    | Ct                   | Ct
    | Pa                   | Pa
    | So                   | So
    | Ne;;                 | Ne
 
let x = St;;          let x = St
 
x;;                   printf "%A\n" x

Opět se tedy jedná o nepatrnou změnu syntaxe, nikoli sémantiky.

6. Datový typ n-tice (tuple)

Datový typ n-tice byl z pohledu programovacího jazyka F# popsán minule v sedmé kapitole. V jazyku OCaml se používá naprosto stejná deklarace a i samotné hodnoty typu n-tice lze zpracovávat zcela stejným způsobem, včetně destructuringu (není divu, jedná se o dědictví ze společného prapředka – jazyka ML):

(* OCaml *)                                   (* F# *)
 
type rectangle = int * int;;                  type Rectangle = int * int
 
let print_rectange r =                        let print_rectange r =
  let (width, height) = r in                      let (width, height) = r in
  Printf.printf "rect: %dx%d\n" width height          printf "rect: %dx%d\n" width height
;;
 
let r1 = (10, 20);;                           let r1 = (10, 20)
 
print_rectange r1;;                           print_rectange r1
Poznámka: pro oba popisované jazyky je typické, že konstruktor je zapisován stejně jako výraz s „rozpadem“ n-tice na jednotlivé prvky.

7. N-tice a pattern matching

Při čtení prvků z n-tice se často 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. Samozřejmě opět porovnáme variantu napsanou v OCamlu s variantou naprogramovanou v jazyku F#:

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

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):

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

Shodné pojmenování typu a prvku sjednocení v jazyce F# většinou v OCaml nevyužijeme:

(* OCaml *)                                                               (* F# *)
 
type rectangle = Rectangle of int * int;;                                 type Rectangle = Rectangle of int * int
 
let print_rectange (r:rectangle) =                                        let print_rectange (r : Rectangle) =
  match r with                                                                match r with
  | Rectangle(width, height) -> Printf.printf "rect: %dx%d\n" width height    | Rectangle(width, height) -> printf "rect: %dx%d\n" width height
;;
 
let r1 = Rectangle(10, 20);;                                              let r1 = Rectangle(10, 20)
 
print_rectange r1;;                                                       print_rectange r1

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

Minule jsme si taktéž ukázali velmi důležitý rys ML jazyků – možnost definovat typ reprezentující několik různých hodnot, které samy o sobě nejsou stejného typu. Příkladem je typ nazvaný Shape, který ve skutečnosti znamená, že buď pracujeme s hodnotou typu Rectangle nebo hodnotou typu Circle. Použijeme zde disjunktní sjednocení, které se v obou jazycích, tj. jak v OCamlu, tak i v jazyku F#, zapisuje prakticky totožným způsobem:

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

V praxi se velmi často setkáme s tím, že deklarace typu Shape/shape se zapisuje na více řádcích, aby tak po vizuální stránce odpovídala blokům match, v nichž s hodnotami tohoto typu pracujeme (každý konkrétní typ pak začíná řádkem začínajícím znakem |):

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

9. Rekurzivní datová struktura: výraz

Disjunktní sjednocení zkombinované s n-ticemi ve skutečnosti představuje velmi silný rys programovacích jazyků F# i OCaml. Tento rys 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í. Příkladem je reprezentace výrazu (expression); ostatně právě OCaml se často používá při implementaci překladačů, kde se s podobnými objekty můžeme velmi často setkat. Zápis takového rekurzivního typu je v obou jazycích prakticky totožný:

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

10. Rekurzivní generická datová struktura: strom

Možnosti typového systému jazyků OCaml a F# jdou ve skutečnosti ještě dále, protože můžeme vytvořit generický rekurzivní datový typ. Tentokrát se bude jednat o datový typ představující strom (přesněji řečeno binární strom), což je pochopitelně rekurzivní datová 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). V jazyku OCaml se v tomto případě používá poněkud odlišný zápis – podle mého skromného názoru čitelnější, než v případě F#, ovšem F# je v tomto ohledu poplatný jazykům odvozeným od C++ či Javy:

(* OCaml *)                                            (* F# *)
 
type 'a tree =                                         type Tree<'a> =
  | E                                                      | E
  | T of 'a tree * 'a * 'a tree                            | T of Tree<'a> * 'a * Tree<'a>
;;
 
let t1 = T(E, "foo", E);;                              let t1 = T(E, "foo", E)
let t2 = T(T(E, "foo", E), "bar", T(E, "baz", E));;    let t2 = T(T(E, "foo", E), "bar", T(E, "baz", E))
 
t1;;                                                   printf "%A\n" t1
t2;;                                                   printf "%A\n" t2

11. Třídy a objekty v ML jazycích

Písmeno „O“ v názvu jazyka OCaml znamená „objective“, což nám prozrazuje, že tento programovací jazyk nabízí programátorům možnost práce s objekty (jejichž typem je třída). Zatímco v OCamlu se jednalo o více či méně užitečnou „úlitbu“ dobovým požadavkům, je podpora objektově orientovaného programování v jazyku F# prakticky nutností, protože programy psané v tomto jazyku musí spolupracovat s dalšími jazyky v ekosystému .NET. Z tohoto důvodu si v dalších kapitolách připomeneme základy OOP v jazyku F# i to, jak se podobné koncepty realizují v jazyku OCaml (jenž je starší a nebyl navržen tak, aby se podobal například C++).

12. Deklarace třídy

Podívejme se nyní na deklaraci jednoduché třídy Rectangle, jejíž instance budou mít dva atributy nazvané X a Y (rozměry v jednotlivých osách) a s konstruktorem, který akceptuje dva parametry typu int (výchozí hodnoty rozměrů). Zde se již syntaxe obou jazyků poměrně významně odlišuje:

(* OCaml *)                         (* F# *)
 
class rectangle (x:int) (y:int) =   type Rectangle(x: int, y: int) =
  object (self)                         member this.X = x
    val x = x                           member this.Y = y
    val y = y
  end;;
 
  
let r1 = new rectangle 10 20;;      let r1 = Rectangle(10, 20)
 
r1;;                                printf "%A\n" r1
Poznámka: v tomto případě je zápis v programovacím jazyku F# řešen poměrně elegantnějším způsobem – typ „třída“ je na stejné úrovni, jako jakýkoli jiný typ.

13. Metoda deklarovaná ve třídě

Do deklarace třídy můžeme přidat i metody. Například se může jednat o metodu nazvanou Print (v OCamlu print), která vytiskne jak název objektu, tak i jeho atributy. Zde již narazíme na dnes možná poněkud zvláštní způsob zápisu volání metody v OCamlu, kdy se namísto tečkové notace používá křížek (ale samozřejmě je snadné si na to zvyknout):

(* OCaml *)                                                (* F# *)
 
class rectangle (x:int) (y:int) =                          type Rectangle(x: int, y: int) =
  object (self)                                                member this.X = x
    val x = x                                                  member this.Y = y
    val y = y                                                  member this.Print() =
    method print = Printf.printf "Rectangle: %dx%d\n" x y          printf "Rectangle: %dx%d\n" x y
  end;;
 
let r1 = new rectangle 10 20;;                             let r1 = Rectangle(10, 20)
 
r1#print;;                                                 r1.Print()

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

Ve shodně očíslované čtrnácté kapitole jsme si minule řekli, že se relativně často 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í).

Realizace v obou porovnávaných jazycích by mohla vypadat následovně:

(* OCaml *)                                                          (* F# *)
 
class rectangle (x:int) (y:int) =                                    type Rectangle(x: int, y: int) =
  object (self)                                                          member this.X = x
    val x = x                                                            member this.Y = y
    val y = y                                                            member this.Print() =
    method print = Printf.printf "Rectangle: %dx%d\n" x y                    printf "Rectangle: %dx%d\n" this.X this.Y
    method enlarge (xd:int) (yd:int) = new rectangle (x+xd) (y+yd)       member this.Enlarge(dx, dy) =
  end;;                                                                      Rectangle(this.X + dx, this.Y + dy)
 
let r1 = new rectangle 10 20;;                                       let r1 = Rectangle(10, 20)
let r2 = r1#enlarge 1 2;;                                            let r2 = r1.Enlarge(1, 2)
 
r1#print;;                                                           r1.Print()
r2#print;;                                                           r2.Print()

15. Přetížení operátoru pro instance třídy

V dnešním posledním demonstračním příkladu, v němž budeme porovnávat sémantické a syntaktické shody a rozdíly mezi programovacími jazyky OCaml a F#, si ukážeme definici přetíženého operátoru pro instance třídy Vector, resp. vector. V případě jazyka OCaml je tento operátor přetížen na úrovni modulu, zatímco v jazyku F# můžeme operátor definovat jako statickou metodu třídy Vector. Výsledek ovšem bude stejný – možnost sčítat vektory tak, jak je to běžné v matematice, tedy s využitím k tomu určeného (přetíženého) operátoru +:

(* OCaml *)                                           (* F# *)
 
class vector (x:int) (y:int) =                        type Vector(x: int, y: int) =
  object (self)                                           member this.X = x
    val x = x                                             member this.Y = y
    val y = y                                             member this.Print() =
    method print = Printf.printf "Vector: %dx%d\n" x y        printf "Vector: %dx%d\n" this.X this.Y
    method get_x = x
    method get_y = y
  end;;
 
let(+) (a: vector) (b: vector) =                          static member (+) (a : Vector, b : Vector) =
    new vector (a#get_x+b#get_x) (a#get_y+b#get_y);;          Vector(a.X + b.X, a.Y + b.Y)
 
let v1 = new vector 10 20;;                           let v1 = Vector(10, 20)
v1#print;;                                            v1.Print()
 
let v2 = new vector 1 2;;                             let v2 = Vector(1, 2)
v2#print;;                                            v2.Print()
 
let v3 = v1 + v2;;                                    let v3 = v1 + v2
v3#print;;                                            v3.Print()
Poznámka: původní funkcionalita operátoru + však nebude v případě jazyka OCaml zachována! Použijte raději jiný operátor:
let(+@) (a: vector) (b: vector) = new vector (a#get_x+b#get_x) (a#get_y+b#get_y);;
Poznámka: zde můžeme vidět nejenom syntaktický rozdíl, ale i rozdíl v sémantice.

16. Deklarace přetíženého operátoru a automatické odvození typů operandů

Díky algoritmu typové inference je možné vynechat explicitní určení typů parametrů pro nově definovaný (či přetížený) operátor. Výsledkem bude kratší programový kód, který však od programátora již vyžaduje znalost kontextu:

class vector x y =
  object (self)
    val x = x
    val y = y
    method print = Printf.printf "Vector: %dx%d\n" x y
    method get_x = x
    method get_y = y
  end;;
 
let(+?) a b = new vector (a#get_x+b#get_x) (a#get_y+b#get_y);;
 
let v1 = new vector 10 20;;
v1#print;;
 
let v2 = new vector 1 2;;
v2#print;;
 
let v3 = v1 +? v2;;
v3#print;;

17. Kam dál? GADT

Až doposud bylo patrné, že jazyky F# a OCaml mají prakticky totožnou sémantiku a většinou i velmi podobnou syntaxi. Ovšem právě v oblasti typových systémů se začínají oba jazyky postupně rozcházet. Je tomu tak především proto, že v OCamlu lze od verze 4.00 používat takzvaný GADT neboli Generalized algebraic data type. Jedná se o velmi zajímavý a užitečný koncept, kterému se budeme věnovat v samostatném článku (resp. s velkou pravděpodobností ve dvou článcích). Ovšem stále nám zbývá popis společných vlastností obou jazyků. Například jsme se doposud nezabývali všemi řídicími konstrukcemi jazyků F# a OCaml atd.

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/ocaml-examples/. V tabulce umístěné pod tímto odstavcem jsou uvedeny odkazy na tyto příklady:

# Příklad Popis příkladu Cesta
1 article01/hello_world1.ml zavolání funkce print_string https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/hello_world1.ml
2 article01/hello_world2.ml zavolání funkce printf.Printf https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/hello_world2.ml
       
3 article01/function.ml definice funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/function.ml
4 article01/lambda.ml anonymní funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/lambda.ml
       
5 article01/function_type1.ml explicitní specifikace typu návratové hodnoty funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/function_type1.ml
6 article01/function_type2.ml explicitní specifikace typu návratové hodnoty funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/function_type2.ml
       
7 article01/call_function1.ml definice jednoduché funkce s jejím zavoláním https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/call_function1.ml
8 article01/call_function2.ml definice jednoduché funkce s jejím zavoláním https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/call_function2.ml
9 article01/call_function3.ml použití operátoru + pro dvojici hodnot typu float https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/call_function3.ml
10 article01/call_function4.ml použití operátoru +. pro dvojici hodnot typu float https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/call_function4.ml
11 article01/call_function5.ml plná deklarace funkce bez syntaktického cukru https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/call_function5.ml
12 article01/call_function6.ml plná deklarace funkce bez syntaktického cukru https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/call_function6.ml
       
13 article01/local_binding1.ml definice lokálních symbolů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/local_binding1.ml
14 article01/local_binding2.ml definice lokálních symbolů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle01/local_binding2.ml
       
15 article02/basic_binding.ml navázání hodnoty na symbol (deklarace proměnné) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/basic_binding.ml
16 article02/print_variable.ml tisk hodnoty proměnné https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/print_variable.ml
17 article02/variables_and_functions.ml předání proměnné do funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/variables_and_functi­ons.ml
18 article02/redefine_symbol1.ml pokus o redefinici symbolu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/redefine_symbol1.ml
19 article02/redefine_symbol2.ml pokus o redefinici symbolu (složitější příklad) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/redefine_symbol2.ml
       
20 article02/requal_operator1.ml operátor = https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/equal_operator1.ml
21 article02/requal_operator2.ml operátor = https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/equal_operator2.ml
       
22 article02/immutable_variable.ml „změna“ neměnitelné proměnné https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/immutable_variable.ml
22 article02/mutable_variable.ml změna měnitelné proměnné https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/mutable_variable.ml
23 article02/shadow.ml shadowing symbolu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/shadow.ml
24 article02/incr.ml standardní funkce incr https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/incr.ml
25 article02/ident.ml nejjednodušší polymorfická funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/ident.ml
       
26 article02/tuple1.ml datový typ n-tice (tuple) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/tuple1.ml
27 article02/tuple2.ml datový typ n-tice (tuple) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/tuple2.ml
28 article02/record1.ml datový typ záznam (record), deklarace proměnné tohoto typu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/record1.ml
29 article02/record2.ml datový typ záznam (record) a typová inference https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/record2.ml
       
30 article02/unit.ml datový typ unit a rozdíl oproti funkcím bez parametrů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/unit.ml
31 article02/polymorphic.ml použití polymorfických funkcí https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/polymorphic.ml
32 article02/two_same_records.ml dva datové typy záznam se shodnými prvky https://github.com/tisnik/ocaml-examples/tree/master/arti­cle02/two_same_records.ml
       
33 article03/recursion1.ml pokus o deklaraci funkce s přímou rekurzí založený na let https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/recursion1.ml
34 article03/recursion2.ml deklarace funkce s přímou rekurzí založená na let rec https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/recursion2.ml
35 article03/recursion3.ml využití tail rekurze pro výpočet členu Fibonacciho posloupnosti https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/recursion3.ml
36 article03/recursion4.ml obyčejná nerekurzivní funkce definovaná přes let rec https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/recursion4.ml
       
37 article03/odd_even1.ml nepřímá rekurze (nekorektní varianta) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/odd_even1.ml
38 article03/odd_even2.ml nepřímá rekurze (taktéž nekorektní varianta) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/odd_even2.ml
39 article03/odd_even3.ml jediný korektní zápis nepřímé rekurze https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/odd_even3.ml
40 article03/odd_even4.ml nepřímá rekurze bez použití klíčového slova rec https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/odd_even4.ml
       
41 article03/pattern1.ml výpočet Faktoriálu založený na pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/pattern1.ml
42 article03/pattern2.ml výpočet Faktoriálu založený na pattern matchingu, sloučení vstupů se stejným výstupem https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/pattern2.ml
43 article03/pattern3.ml kontrola neplatného vstupu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/pattern3.ml
44 article03/pattern4.ml pattern matching pro větší množství hodnot https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/pattern4.ml
45 article03/pattern5.ml rekurzivní implementace Ackermannovy funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/pattern5.ml
46 article03/pattern6.ml kontrola neplatných vstupních hodnot pro Ackermannovu funkci https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/pattern6.ml
       
47 article03/fibonacci1.ml výpočet Fibonacciho posloupnosti založený na pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/fibonacci1.ml
48 article03/fibonacci2.ml výpočet Fibonacciho posloupnosti založený na pattern matchingu (více idiomatický zápis) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/fibonacci2.ml
       
49 article03/first.ml funkce vracející první prvek z dvojice založená na pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/first.ml
50 article03/second.ml funkce vracející druhý prvek z dvojice založená na pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/second.ml
51 article03/zero_coordinate.ml test na nulovou souřadnici/souřadnice založený na pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/zero_coordinate.ml
       
52 article03/get_model.ml získání prvku ze záznamu (opět založeno na pattern matchingu) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/get_model.ml
       
53 article03/list_literal1.ml seznam se třemi prvky typu celé číslo https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/list_literal1.ml
54 article03/list_literal2.ml seznam se třemi prvky typu řetězec https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/list_literal2.ml
55 article03/list_literal3.ml seznam se třemi prvky typu n-tice https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/list_literal3.ml
56 article03/list_literal4.ml nekorektní pokus o vytvoření seznamu s prvky různých typů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/list_literal4.ml
57 article03/empty_list.ml konstrukce prázdného seznamu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/empty_list.ml
       
58 article03/head_tail1.ml složení seznamu se dvěma prvky s využitím operátoru :: https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/head_tail1.ml
59 article03/head_tail2.ml složení seznamu se třemi prvky s využitím operátoru :: https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/head_tail2.ml
       
60 article03/list_properties.ml vlastnosti (properties) seznamů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/list_properties.ml
61 article03/len1.ml naivní rekurzivní výpočet délky seznamu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/len1.ml
62 article03/len2.ml vylepšený rekurzivní výpočet délky seznamu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/len2.ml
63 article03/len3.ml vylepšený rekurzivní výpočet délky seznamu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/len3.ml
       
64 article03/join_lists.ml spojení dvou seznamů operátorem :: https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/join_lists.ml
65 article03/append1.ml implementace spojení dvou seznamů rekurzivním výpočtem https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/append1.ml
66 article03/append2.ml implementace spojení dvou seznamů rekurzivním výpočtem, použití pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/append2.ml
       
67 article03/sum1.ml součet hodnot všech prvků v seznamu (bez tail rekurze) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/sum1.ml
68 article03/sum2.ml součet hodnot všech prvků v seznamu (s využitím tail rekurze) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/sum2.ml
       
69 article03/print_int_list.ml tisk seznamu celých čísel https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/print_int_list.ml
70 article03/print_string_list.ml tisk seznamu řetězců https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/print_string_list.ml
71 article03/print_list_prefix.ml tisk seznamu s prefixem https://github.com/tisnik/ocaml-examples/tree/master/arti­cle03/print_list_prefix.ml
       
72 article04/none_value.ml hodnota None https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/none_value.ml
73 article04/some_value1.ml hodnota Some(typ) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/some_value1.ml
74 article04/some_value2.ml hodnota Some(typ) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/some_value2.ml
75 article04/some_value3.ml hodnota Some(typ) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/some_value3.ml
76 article04/option_exists1.ml základní pattern matching, korektní varianta https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_exists1.ml
77 article04/option_exists2.ml základní pattern matching, nekorektní varianta https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_exists2.ml
78 article04/option_exists3.ml základní pattern matching, nekorektní varianta https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_exists3.ml
79 article04/find_in_list1.ml vyhledávání prvku v seznamu založené na pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/find_in_list1.ml
80 article04/find_in_list2.ml varianta předchozího programu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/find_in_list2.ml
81 article04/option_get.ml pokus o přečtení hodnoty obalené typem Option https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_get.ml
82 article04/is_none_is_some.ml predikáty is_none a is_some https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/is_none_is_some.ml
83 article04/option_equal.ml ekvivalence dvou obalených hodnot https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_equal.ml
84 article04/some_none.ml obalení obalené hodnoty https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/some_none.ml
       
85 article04/result_divide1.ml ukázka použití datového typu Result https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/result_divide1.ml
86 article04/result_divide2.ml ukázka použití datového typu Result a pattern matchingu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/result_divide2.ml
87 article04/result_divide3.ml stejné jako result_divide1.fs, ovšem bez explicitního zápisu typů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/result_divide3.ml
88 article04/result_divide4.ml stejné jako result_divide2.fs, ovšem bez explicitního zápisu typů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/result_divide4.ml
       
89 article04/array_value.ml deklarace pole výčtem jeho prvků https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_value.ml
90 article04/array_make.ml funkce Array.make pro konstrukci pole https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_make.ml
91 article04/array_init1.ml inicializace prvků pole funkcí Array.init https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_init1.ml
92 article04/array_init2.ml inicializace prvků pole funkcí Array.init https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_init2.ml
93 article04/array_init3.ml inicializace prvků pole funkcí Array.init https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_init3.ml
94 article04/array_indexing.ml indexování prvků pole https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_indexing.ml
95 article04/array_mutation.ml mutace pole: modifikace hodnot jeho prvků https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/array_mutation.ml
       
96 article04/option_no_bind.ml zřetězení volání funkcí, které si předávají hodnoty typu Option – neidiomatické řešení https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_no_bind.ml
97 article04/option_bind.ml řešení založené na bind https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/option_bind.ml
98 article04/bind_infix_operator.ml funkce Option.bind zapsaná formou infixového operátoru https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/bind_infix_operator­.ml
99 article04/bind_infix_operator2.ml zřetězení funkcí s využitím Result.bind https://github.com/tisnik/ocaml-examples/tree/master/arti­cle04/bind_infix_operator.ml
       
100 article05/unary_arithmetic.ml unární aritmetické operátory https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/unary_arithmetic.ml
101 article05/binary_arithmetic.ml binární aritmetické operátory https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/binary_arithmetic.ml
102 article05/boolean_operators.ml booleovské operátory https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/boolean_operators.ml
103 article05/relational.ml základní čtveřice relačních operátorů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/relational.ml
104 article05/equality.ml operátory zjišťující ekvivalenci hodnot https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/equality.ml
105 article05/joins.ml operátory pro spojení řetězců a seznamů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/joins.ml
106 article05/references.ml operátory pro práci s referencemi https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/references.ml
107 article05/function_operators.ml operátory pro aplikaci funkcí https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/function_operators.ml
108 article05/conwoy.ml konvoj vytvořený operátorem |> https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/conwoy.ml
       
109 article05/usage_unary_arithmetic.ml test unárních operátorů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_unary_arithme­tic.ml
110 article05/usage_binary_arithmetic.ml test binárních operátorů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_binary_arithme­tic.ml
111 article05/usage_boolean.ml test booleovských operátorů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_boolean.ml
112 article05/usage_relational.ml test relačních operátorů vůči různým hodnotám https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_relational.ml
113 article05/usage_relational_tuples.ml test relačních operátorů vůči n-ticím https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_relational_tu­ples.ml
114 article05/usage_equality.ml testy na strukturální a fyzickou rovnost https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_equality.ml
115 article05/usage_joins.ml testy operátorů pro spojení řetězců a seznamů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_joins.ml
116 article05/usage_function.ml testy operátorů pro aplikaci funkcí https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/usage_function.ml
       
117 article05/operator_unary1.ml vlastní unární operátor https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/operator_unary1.ml
118 article05/operator_unary2.ml vlastní unární operátory https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/operator_unary2.ml
119 article05/operator_binary1.ml vlastní binární operátor s asociativitou zleva https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/operator_binary1.ml
120 article05/operator_binary2.ml vlastní binární operátor s asociativitou zprava https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/operator_binary2.ml
121 article05/operator_binary3.ml vlastní binární operátory s rozdílnou prioritou https://github.com/tisnik/ocaml-examples/tree/master/arti­cle05/operator_binary3.ml
       
122 article06/circle_rectangle1.ml datový typ přestavující buď kružnici nebo obdélník https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/circle_rectangle1.ml
123 article06/circle_rectangle2.ml datový typ přestavující buď kružnici nebo obdélník https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/circle_rectangle2.ml
124 article06/enum1.ml příklad použití datového typu výčet https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/enum1.ml
125 article06/enum2.ml příklad použití datového typu výčet https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/enum2.ml
126 article06/expr.ml datový typ představující rekurzivní definici výrazu (expression) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/expr.ml
       
127 article06/object1.ml jednoduchá třída s dvojicí atributů https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/object1.ml
128 article06/object2.ml přidání metody do třídy https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/object2.ml
129 article06/object3.ml metoda vytvářející nový objekt https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/object3.ml
130 article06/object4.ml doplnění předchozí třídy o přetížený operátor + https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/object4.ml
131 article06/object5.ml doplnění předchozí třídy o přetížený operátor + s automatickým odvozením typu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/object5.ml
       
132 article06/rectangle1.ml typ Rectangle založený na n-tici https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/rectangle1.ml
133 article06/rectangle2.ml úprava předchozího příkladu; pattern matching https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/rectangle2.ml
134 article06/rectangle3.ml úprava předchozího příkladu, explicitní pojmenování https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/rectangle3.ml
135 article06/rectangle4.ml různé jmenné prostory https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/rectangle4.ml
       
136 article06/struct_type1.ml definice záznamu (record, struct) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/struct_type1.ml
137 article06/struct_type2.ml rozšíření o funkci pro tisk záznamu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/struct_type2.ml
138 article06/struct_type3.ml automatické odvození datového typu parametru funkce https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/struct_type3.ml
139 article06/struct_type4.ml otestování mezí automatického odvozování typů parametrů (nefunkční varianta) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/struct_type4.ml
140 article06/struct_type5.ml otestování mezí automatického odvozování typů parametrů (funkční varianta) https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/struct_type5.ml
141 article06/tree.ml datový typ představující rekurzivní definici binárního stromu https://github.com/tisnik/ocaml-examples/tree/master/arti­cle06/tree.ml

19. 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. Try OCaml
    https://try.ocaml.pro/
  23. CSE 341: Functions and patterns
    https://courses.cs.washin­gton.edu/courses/cse341/04wi/lec­tures/03-ml-functions.html
  24. Comparing Objective Caml and Standard ML
    http://adam.chlipala.net/mlcomp/
  25. 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
  26. Cheat Sheets (pro OCaml)
    https://www.ocaml.org/doc­s/cheat_sheets.html
  27. Think OCaml: How to Think Like a (Functional) Programmer
    https://www.greenteapress­.com/thinkocaml/thinkocam­l.pdf
  28. The OCaml Language Cheat Sheet
    https://ocamlpro.github.io/ocaml-cheat-sheets/ocaml-lang.pdf
  29. Syllabus (FAS CS51)
    https://cs51.io/college/syllabus/
  30. Abstraction and Design In Computation
    http://book.cs51.io/
  31. Learn X in Y minutes Where X=Standard ML
    https://learnxinyminutes.com/doc­s/standard-ml/
  32. CSE307 Online – Summer 2018: Principles of Programing Languages course
    https://www3.cs.stonybrook­.edu/~pfodor/courses/summer/cse307­.html
  33. CSE307 Principles of Programming Languages course: SML part 1
    https://www.youtube.com/wat­ch?v=p1n0_PsM6hw
  34. CSE 307 – Principles of Programming Languages – SML
    https://www3.cs.stonybrook­.edu/~pfodor/courses/summer/CSE307/L01_SML­.pdf
  35. SML, Some Basic Examples
    https://cs.fit.edu/~ryan/sml/in­tro.html
  36. History of programming languages
    https://devskiller.com/history-of-programming-languages/
  37. History of programming languages (Wikipedia)
    https://en.wikipedia.org/wi­ki/History_of_programming_lan­guages
  38. 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/
  39. The Evolution Of Programming Languages
    https://www.i-programmer.info/news/98-languages/8809-the-evolution-of-programming-languages.html
  40. Evoluce programovacích jazyků
    https://ccrma.stanford.edu/cou­rses/250a-fall-2005/docs/ComputerLanguagesChart.png
  41. Poly/ML Homepage
    https://polyml.org/
  42. PolyConf 16: A brief history of F# / Rachel Reese
    https://www.youtube.com/wat­ch?v=cbDjpi727aY
  43. Programovací jazyk Clojure 18: základní techniky optimalizace aplikací
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  44. Moscow ML Language Overview
    https://itu.dk/people/ses­toft/mosml/mosmlref.pdf
  45. ForLoops
    http://mlton.org/ForLoops
  46. Funkcionální dobrodružství v JavaScriptu
    https://blog.kolman.cz/2015/12/fun­kcionalni-dobrodruzstvi-v-javascriptu.html
  47. Recenze knihy Functional Thinking (Paradigm over syntax)
    https://www.root.cz/clanky/recenze-knihy-functional-thinking-paradigm-over-syntax/
  48. Currying
    https://sw-samuraj.cz/2011/02/currying/
  49. Používání funkcí v F#
    https://docs.microsoft.com/cs-cz/dotnet/fsharp/tutorials/using-functions
  50. Funkce vyššího řádu
    http://naucte-se.haskell.cz/funkce-vyssiho-radu
  51. Currying (Wikipedia)
    https://en.wikipedia.org/wi­ki/Currying
  52. Currying (Haskell wiki)
    https://wiki.haskell.org/Currying
  53. Haskell Curry
    https://en.wikipedia.org/wi­ki/Haskell_Curry
  54. Moses Schönfinkel
    https://en.wikipedia.org/wi­ki/Moses_Sch%C3%B6nfinkel
  55. .NET framework
    https://dotnet.microsoft.com/en-us/
  56. F# – .NET Blog
    https://devblogs.microsof­t.com/dotnet/category/fshar­p/
  57. Playground: OCaml
    https://ocaml.org/play
  58. The F# Survival Guide
    https://web.archive.org/web/20110715231625/htt­p://www.ctocorner.com/fshar­p/book/default.aspx
  59. Object-Oriented Programming — The Trillion Dollar Disaster
    https://betterprogramming.pub/object-oriented-programming-the-trillion-dollar-disaster-92a4b666c7c7
  60. Goodbye, Object Oriented Programming
    https://cscalfani.medium.com/goodbye-object-oriented-programming-a59cda4c0e53
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. Don Syme
    https://en.wikipedia.org/wi­ki/Don_Syme
  68. Python to OCaml: Retrospective
    http://roscidus.com/blog/blog/2014/06/0­6/python-to-ocaml-retrospective/
  69. Why does Cambridge teach OCaml as the first programming language?
    https://www.youtube.com/wat­ch?v=6APBx0WsgeQ
  70. OCaml and 7 Things You Need To Know About It In 2021 | Functional Programming | Caml
    https://www.youtube.com/wat­ch?v=s0itOsgcf9Q
  71. OCaml 2021 – 25 years of OCaml
    https://www.youtube.com/watch?v=-u_zKPXj6mw
  72. Introduction | OCaml Programming | Chapter 1 Video 1
    https://www.youtube.com/wat­ch?v=MUcka_SvhLw&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU
  73. Functional Programming – What | OCaml Programming | Chapter 1 Video 2
    https://www.youtube.com/wat­ch?v=JTEwC3HihFc&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=2
  74. Functional Programming – Why Part 1 | OCaml Programming | Chapter 1 Video 3
    https://www.youtube.com/wat­ch?v=SKr3ItChPSI&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=3
  75. Functional Programming – Why Part 2 | OCaml Programming | Chapter 1 Video 4
    https://www.youtube.com/wat­ch?v=eNLm5Xbgmd0&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=4
  76. OCaml | OCaml Programming | Chapter 1 Video 5
    https://www.youtube.com/watch?v=T-DIW1dhYzo&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=5
  77. Five Aspects of Learning a Programming Language | OCaml Programming | Chapter 2 Video 1
    https://www.youtube.com/wat­ch?v=A5IHFZtRfBs&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=6
  78. Expressions | OCaml Programming | Chapter 2 Video 2
    https://www.youtube.com/watch?v=3fzrFY-2ZQ8&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=7
  79. If Expressions | OCaml Programming | Chapter 2 Video 3
    https://www.youtube.com/wat­ch?v=XJ6QPtlPD7s&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=8
  80. Let Definitions | OCaml Programming | Chapter 2 Video 4
    https://www.youtube.com/wat­ch?v=eRnG4gwOTlI&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=10
  81. Let Expressions | OCaml Programming | Chapter 2 Video 5
    https://www.youtube.com/wat­ch?v=ug3L97FXC6A&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=10
  82. Variable Expressions and Scope | OCaml Programming | Chapter 2 Video 6
    https://www.youtube.com/wat­ch?v=_TpTC6eo34M&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=11
  83. Scope and the Toplevel | OCaml Programming | Chapter 2 Video 7
    https://www.youtube.com/wat­ch?v=4SqMkUwakEA&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=12
  84. Anonymous Functions | OCaml Programming | Chapter 2 Video 8
    https://www.youtube.com/wat­ch?v=JwoIIrj0bcM&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=13
  85. Lambdas | OCaml Programming | Chapter 2 Video 9
    https://www.youtube.com/wat­ch?v=zHHCD7MOjmw&list=PLre5AT9JnKShBO­PeuiD9b-I4XROIJhkIU&index=15
  86. Operators
    https://ocaml.org/docs/operators
  87. Operator overloading
    https://en.wikipedia.org/wi­ki/Operator_overloading
  88. Generalized algebraic data type
    https://en.wikipedia.org/wi­ki/Generalized_algebraic_da­ta_type
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.