Haskell Hero
Interaktivní učebnice pro začínající Haskellisty
|
Typy IIVytváříme nové krabičkyJak jsme si ukázali v lekci Typy I, v Haskellu máme k dispozici krabičku všech celých čísel, krabičku všech znaků nebo třeba krabičku dvou logických hodnot. Někdy je výhodné vytvořit si novou krabičku a do ní nasypat hodnoty, se kterými chceme pracovat. PříkladVytvořte datový typ, který bude obsahovat všechny čtverce zadané délkou strany a všechny obdélníky zadané délkou své výšky a šířky. Délku vyjádřete celým číslem.
Pojmenujme si náš nový datový typ například
Například čtverec o délce strany 4 bude vypadat
Obdélník šířky 7 a délky 2 bude vypadat
Obecně chceme vytvořit krabičku data Obrazec = Ctverec Integer | Obdelnik Integer IntegerPoznámka: Pokud bychom chtěli pracovat s obrazci, které nebudou mít celočíselné rozměry, místo typu Integer použijeme Float nebo Double .
Umíme tedy definovat datový typ
Mohli bychom například vytvořit datový typ data Slovnik = Slovo StringZde můžeme String nahradit libovolným řetězcem. Tento datový typ obsahuje například hodnoty:
Slovo "Ahoj" Slovo "Haskell" Slovo "@{Đđ÷" Pracujeme s novými krabičkamiNyní, když máme vytvořenou krabičku všech čtverců a obdélníků, s ní můžeme začít pracovat jako s každým jiným datovým typem. Příklad
Definujte funkce
Nejdříve ze všeho musíme uvést naši definici datového typu data Obrazec = Ctverec Integer | Obdelnik Integer Integer
Obě funkce budou typu obvod :: Obrazec -> Integer obsah :: Obrazec -> Integer
A teď již k samotným definicím. Už ze základní školy víme, že obvod čtverce, který má délku strany obvod :: Obrazec -> Integer obvod (Ctverec x) = 4 * x
Pozor na závorky! V typové anotaci uvádíme, že funkce obvod Ctverec x = 4 * xHugs by funkci obvod přiřadil jako parametr datový konstruktor Ctverec a proměnnou x . Přitom funkce obvod očekává, že dostane jednu hodnotu typu Obrazec .
Tuto definici můžeme hned doplnit i na obvod obdélníka. Víme totiž, že obvod obdélníka šířky obvod :: Obrazec -> Integer obvod (Ctverec x) = 4 * x obvod (Obdelnik x y) = 2 * (x + y)
Obdobně zadefinujeme funkci obsah :: Obrazec -> Integer obsah (Ctverec x) = x ^ 2 obsah (Obdelnik x y) = x * y Když se s takto zadefinovanými funkcemi zeptáme Hugse, jaký je obvod obdélníka 5 × 3, bude nám správně sděleno, že 16. obvod (Obdelnik 5 3) ~> 2 * (5 + 3) ~> 2 * 8 ~> 16 Rekurzivní datové typy
Nyní jsme v situaci, kdy umíme zadefinovat jednoduchý datový typ. Někdy se ale může stát, že budeme potřebovat definovat typ složitější. Například bychom chtěli vytvořit datový typ Zero -- nula Succ Zero -- následník nuly - jedna Succ (Succ Zero) -- následník následníka nuly - dva Succ (Succ (Succ Zero)) -- následník následníka následníka nuly - tři ...Jak takový typ zadefinovat? Musíme popsat všechny jeho hodnoty. V příkladu z předchozího odstavce byly hodnoty typu Obrazec buďto Ctverec Integer nebo Obdelnik Integer Integer , kde za Integer můžeme dosadit libovolné celé číslo. Zde máme takové tvary dva:
Kde za data Nat = Zero | Succ NatTakto definovaný datový typ pouze udává strukturu uložení dat v paměti. Není řečeno, jak se mají jeho hodnoty v případě potřeby vypisovat na obrazovku. Nejjednodušší způsob, jak vypisování zprovoznit, je doplnit definici datového typu o řetězec deriving Show . Pozor na malé 'd' a velké 'S'!. Definice typu Nat s umožněným vypisováním na obrazovku tedy bude vypadat následovně:
data Nat = Zero | Succ Nat deriving Show Funkce nad rekurzivními typy
Zde si zadefinujeme jednoduchou funkci nad typem Příklad
Čím začít? Uvědomme si, co můžeme s hodnotami typu
Funkci plusNat :: Nat -> Nat -> Nat plusNat Zero y = y plusNat (Succ x) y = plusNat x (Succ y) |