Typové triedy

Ciele

  1. Pochopiť význam typových tried a ich použitia.
  2. Naučiť sa definovať vlastné inštancie typových tried.
  3. 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.