3.1. Hodnoty a typy

Haskell je čistě funkcionální jazyk, proto se všechny výpočty provádějí tak, že se vyhodnocením výrazů (syntaktických termů) získávají hodnoty (abstraktní entity, které považujeme za odpovědi). S každou hodnotou je svázán její typ. (Intuitivně chápeme typy jako množiny hodnot.) Příkladem výrazů jsou atomické hodnoty jako celé číslo 5, znak 'a' a funkce \x -> x+1, ale také strukturované hodnoty jako je seznam [1,2,3] a dvojice ('b',4).

Stejně jako výrazy označují hodnoty, jsou typové výrazy syntaktické termy označující typové hodnoty (nebo pouze typy). Příklady typových výrazů jsou atomické typy Int (celá čísla s pevně definovanou přesností), Char (znaky), Int->Int (funkce zobrazující Int na Int), stejně jako strukturované typy [Int] (homogenní seznamy celých čísel) a (Char,Int) (dvojice znak, celé číslo).

Všechny hodnoty v jazyce Haskell jsou „plnoprávné“ - mohou být předávány jako argumenty funkcím, vráceny jako výsledky, umístěny v datových strukturách atd. Na druhé straně typy jazyka Haskell nejsou plnoprávné. Typy v jistém smyslu popisují hodnoty a propojení hodnoty s jejím typem se označuje jako typování. Pomocí výše uvedených příkladů hodnot a typů zapisujeme typování takto:

5       :: Int
'a'     :: Char
inc     :: Int -> Int
[1,2,3] :: [Int]
('b',4) :: (Char,Int)
Symbol „::“ můžeme číst jako „má typ.“

Funkce se v jazyce Haskell normálně definují posloupností rovnic. Například funkci inc můžeme definovat jedinou rovnicí:

inc n = n+1
Rovnice je příkladem deklarace. Dalším druhem deklarace je deklarace signatury typu, pomocí níž můžeme deklarovat explicitní typování pro inc:
inc :: Int -> Int

Pokud budeme chtít uvést, že se výraz e1 vyhodnotí, nebo též „zredukuje“ na jiný výraz nebo hodnotu e2, budeme psát:

e1 => e2

Například můžeme psát, že:

inc (inc 3) => 5

Statický typový systém definuje formální vztah mezi typy a hodnotami. Statický typový systém zajišťuje, že programy v Haskellu jsou typově bezpečné, tj. že programátor nějakým způsobem nezpůsobil nějaký zmatek. Například obecně nelze sečítat dva znaky, takže výraz 'a'+'b' je špatně typovaný. Hlavní výhoda staticky typovaných jazyků je všeobecně známá: Všechny typové chyby se detekují v době překladu. Ne všechny chyby jsou ale zachyceny typovým systémem; výraz jako 1/0 je typovatelný, ale jeho vyhodnocení způsobí v době provádění výpočtu chybu. I přesto typový systém odhalí v době překladu mnoho chyb, pomáhá uživateli při dokazování programů a umožňuje překladači generovat efektivnější kód (například nejsou v době běhu potřeba žádné testy typových příznaků).

Typový systém rovněž zajišťuje, že uživatelem dodané signatury typů jsou správné. Ve skutečnosti je typový systém jazyka Haskell natolik mocný, že umožňuje (až na pár výjimek popsaných později) uživateli se psaní signatur typů zcela vyhnout. Říkáme, že nám typový systém správný typ odvodí. Nicméně pečlivé uvádění typových signatur, jako jsme učinili v případě inc, je dobrá myšlenka, neboť typové signatury jsou velmi efektivní formou dokumentace a umožňují vynést na světlo programátorské chyby.


Poznámka:
Poznámka:
Určitě jste si povšimli, že identifikátory označující specifické typy jako Int a Char zapisujeme s velkým počátečním písmenem, zatímco identifikátory označující hodnoty jako inc s malým počátečním písmenem. Není to pouze konvence, ale je to vyžadováno lexikální syntaxí jazyka Haskell. Ve skutečnosti se vždy malá a velká písmena rozlišují: foo, fOo a fOO jsou navzájem různé identifikátory.