Ciele
- Pochopiť význam typových tried a ich použitia.
- Naučiť sa definovať vlastné inštancie typových tried.
- Naučiť sa definovať vlastné typové triedy.
Úvod
V typovej triede sú deklarované funkcie, ktoré každý typ patriaci do danej triedy musí definovať. Napríklad trieda Eq je v štandardnej knižnici definovaná následovne:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y)
Na definovanie toho, že typ patrí do triedy sa používa inštancia typu:
data Point = Point Double Double
data Shape = Circle Point Double
| Rectangle Point Point
instance Eq Point where
Point x1 y1 == Point x2 y2 = x1 == x2 && y1 == y2
instance Eq Shape where
Circle c1 r1 == Circle c2 r2 = c1 == c2 && r1 == r2
Rectangle a1 b1 == Rectangle a2 b2 = a1 == a2 && b1 == b2
_ == _ = False
Pre niektoré zabudované typy je možné použiť automatické odvodenie inštancie pomocou kľúčového slova deriving:
data Point = Point Double Double
deriving (Eq, Show)
data Shape
= Circle Point Double
| Rectangle Point Point
deriving (Eq, Show)
Postup
Krok 1: Použitie typových tried
Úloha 1.1
Implementujte funkciu allEqual, ktorá vráti True ak všetky hodnoty v zozname sú rovné, alebo ak je zoznam prázdny. Aký je typ tejto funkcie?
Úloha 1.2
Upravte definíciu funkcie sumBTree z minulého cvičenia tak, aby dokázala pracovať nielen so stromami obsahujúcimi Integer, ale aj iné numerické typy, napríklad Int alebo Double.
Krok 2: Definovanie inštancií typových tried
Úloha 2.1
Definujte inštanciu typovej triedy Eq pre typ Shape tak, aby obdĺžniky, ktoré sa líšia iba poradím bodov, ktoré ich definujú, boli považované za rovné.
(Rectangle (Point 0 0) (Point 5 5) == Rectangle (Point 5 5) (Point 0 0)) == True
Úloha 2.2
Bolo by možné definovať inštanciu Ord pre typ Shape? Aké by bolo kritérium porovnávania?
Krok 3: Vlastná typová trieda
Majme definované nasledovné dátové typy:
data Point = Point Double Double
deriving (Eq, Show)
data Vector = Vec Double Double
deriving (Eq, Show)
data Shape
= Circle Point Double
| Rectangle Point Point
deriving (Eq, Show)
Úloha 3.1
Definujte typovú triedu Movable s týmito metódami:
move— posunie objekt (druhý argument) o zadaný vektor (prvý argument),reflectX— zrkadlí objekt okolo súradnicovej osi X,reflectY— zrkadlí objekt okolo súradnicovej osi Y,rotate180— otočí objekt o 180° okolo stredu súradnicovej sústavy.
Úloha 3.2
Definujte inštancie triedy Movable pre Point a Shape.
Krok 4: Functor a Foldable
Mnohé funkcie pre prácu s údajovými štruktúrami sú definované nielen pre zoznamy, ale aj pre iné štruktúry. Napríklad okrem funkcie map existuje jej všeobecnejšia forma fmap definovaná pre triedu Functor. Funkcie foldr, foldl a mnohé ďalšie tiež nie sú obmedzené iba pre zoznamu, ale sú definované pre triedu Foldable.
Úloha 4.1
Definujte inštanciu typovej triedy Functor pre typ stromu. Trieda Functor deklaruje funkciu:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Je to všeobecnejšia verzia funkcie map. V prípade stromu zmení vstupnou funkciou každý jeho prvok.
Úloha 4.2
Definujte inštanciu triedy Foldable pre typ BTree. V rámci inštancie implementujte funkciu foldr.
Nech sa „skladanie“ začína aplikáciou zadanej funkcie na každý list stromu a počiatočnú hodnotu. Napríklad, výraz foldr (+) 0 (Branch (Branch (Leaf 1) (Leaf 2)) (Leaf 3)) sa vyhodnotí ako ((1+0) + (2+0)) + (3 + 0).