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
Poznámka
Na rozdiel od predchádzajúceho cvičenia, teraz je Point definovaný ako nový typ a nie synonymum pre dvojicu.
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
Upravte definíciu funkcie sumBTree
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 triedy Show pre typ Exp
z minulého cvičenia.
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
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.