Haskell Hero

Interaktivní učebnice pro začínající Haskellisty

Typy I

Základní typy


Typy jako krabičky

Datový typ je souhrnné označení hodnot se stejnými vlastnostmi.

Krabičkově je to krabička, která obsahuje krabičky stejného tvaru.

  • Integer: všechna celá čísla
  • Int: malá celá čísla (přibližně od − 500 000 000 do 500 000 000)
  • Bool: logické hodnoty
  • Float: desetinná čísla
  • Char: znaky
  • String: řetězce znaků

Že je 1 typu Integer, napíšeme následovně pomocí dvou dvojteček. Tento zápis se nazývá typová anotace.

1 :: Integer
Podobně je to i s dalšími typy:
'v'  :: Char
True :: Bool
5.0  :: Float

Haskell si umí typ funkce odvodit sám, ale pokud mu jej napíšeme, lépe se nám pak budou hledat chyby v našich definicích. Pokud například chceme definovat unární funkci kratPet, která svůj celočíselný argument zpětinásobí. Mohli bychom napsat

kratPet x = even x
a Hugs by to bez připomínky vzal. Problém by nastal až v situaci, kdy bychom tuto funkci poprvé použili a zjistili bychom, že funkce nevrací Integer, ale Bool. Pokud bychom použili typovou anotaci
kratPet  :: Integer -> Integer
kratPet x = even x
přišlo by se na chybu už při nahrávání skriptu do interpretu.

Datové struktury

Uspořádané n-tice

Mějme například uspořádané dvojice (2,'a'), (105,'#') a (-9,'Q'). Všimněme si, že tyto dvojice mají jako svou první složku celé číslo a jako druhou složku znak. Můžeme tedy říct, že všechny tři jsou typu (Integer,Char). Stejně bychom zapsali typ uspořádaných trojic, čtveřic, ...

(True,7), (False,-1)               :: (Bool,Integer)
("Jan",1.0,'w'), ("Jana",2.6, '$') :: (String,Float,Char)
(5,(False,4)), (7,(False,-1))      :: (Integer,(Bool,Integer))
()                                 :: () -- uspořádaná nultice

Seznamy

Narozdíl od uspořádaných n-tic mohou být v seznamu hodnoty pouze jednoho typu. Například [1,2,3,4,5] je seznam celých čísel, čili typu [Integer].

[True,False,False,True]    :: [Bool]
[5.0,6.105,10.89]          :: [Float]
[(5,'a'),(7,'W')]          :: [(Integer,Char)]
     -- seznam dvojic
[[1,2,5],[],[11,14,15,16]] :: [[Integer]]
     -- seznam seznamů celých čísel
Prázdný seznam je sám o sobě bez dalšího upřesnění typu seznam čehokoli.
[] :: [a]

Zvláštní typ seznamu je seznam znaků [Char], který se často zapisuje jako řetězec String. Tyto dva typy jsou libovolně zaměnitelné. [Char] se dá použít v místě, kde se očekává String a String se dá použít v místě, kde se očekává seznam [Char].

String   ≡  [Char]
"Ahoj"   ≡  ['A','h','o','j']
"#&@?!"  ≡  ['#','&','@','?','!']

Typy funkcí

Typová anotace funkce vypadá následovně:

[funkce] :: typ prvního argumentu -> typ druhého argumentu
            -> ... -> typ výsledku

Příklad:

Definujte funkci plus2 včetně typové anotace, která si bere jako argumenty dvě celá čísla a vrátí celé číslo, coby jejich součet.


Taková definice by mohla vypadat následovně:

plus2     ::  Integer -> Integer -> Integer
plus2 x y  =  x + y

Polymorfní typy

Funkce id si bere jeden argument, který v nezměněné podobě vrátí. Je definována takto:

id x = x

Jaký je její typ? Pokud do ní vložíme celé číslo, vrátí celé číslo.

id 5 ~> 5
Takže by její typ mohl být id :: Integer -> Integer.

Pokud bychom jí tento typ přiřadili, zbytečně bychom omezili její použití. Například bychom do ní nemohli vložit seznam Stringů.

id ["abc","DeQ","ASDF"]  ~>  ["abc","DeQ","ASDF"]
A co víc – my bychom chtěli, aby pracovala i s funkcemi.
(id even) 5  ~>  even 5  ~>  False
Tím pádem by musela mít typ
id :: (Integer -> Bool) -> Integer -> Bool

Proto se zavádí polymorfní typy. Zapisují se řetězcem začínajícím malým písmenem, většinou pouze jedním malým písmenem ze začátku abecedy. Tomuto zápisu se říká typová proměnná.

Funkce id je tedy typu id :: a -> a, což znamená dá se do ní vhodit cokoli a ona vrátí hodnotu toho samého typu, jako je hodnota, která do ní byla vhozena.