Dátové typy

Ciele

  1. Vyskúšať prácu s vlastnou dátovou štruktúrou.
  2. Naučiť sa definovať vlastné algebraické údajové typy a funkcie na prácu s nimi.
  3. Pochopiť význam typových parametrov.

Postup

Krok 1: Vlastné dátové typy

Majme dátový typ Date pre reprezentáciu dátumov v tváre rok–mesiac–deň:

data Date = Date Int Int Int
            deriving Show

today = Date 2020 10 14

Úloha 1.1

Definujte funkciu isLastInMonth a pomocou nej funkciu nextDay:

isLastInMonth :: Date -> Bool
nextDay :: Date -> Date

Krok 2: Algebraické dátové typy

Haskell podporuje algebraické dátové typy, takže dátový typ môže mať niekoľko konštruktorov s rôznymi typmi parametrov.

Poznámka

Konštruktor nie je to isté, ako názov typu, no oba sa môžu volať rovnako, hlavne ak je konštruktor iba jeden.

Definujme vlastný typ pre tvary, konkrétne obdĺžnik a kruh:

type Point = (Double, Double)

data Shape = Circle Point Double
           | Rectangle Point Point
           deriving Show

smallCircle = Circle (0, 0) 1
largeCircle = Circle (0, 0) 10
someRectangle = Rectangle (0, 0) (10, 5)
aSquare = Rectangle (0, 0) (10, 10)
shapes = [smallCircle, largeCircle, someRectangle, aSquare]

Poznámka

Pomocou kľúčového slova type definujeme synonymum typu.

Konštuktory typu sa dajú použiť aj pri porovnávaní vzorov na ľavej strane definície funkcie:

area :: Shape -> Double
area (Circle _ r) = pi * r^2
area (Rectangle (x1, y1) (x2, y2)) = (abs (x2-x1)) * (abs (y2-y1))

Úloha 2.1

Definujte funkciu move, ktorá posunie útvar o zadaný vektor:

type Vector = (Double, Double)

move :: Vector -> Shape -> Shape

Krok 3: Parametrický polymorfizmu

Jednotlivé konštruktory môžu mať všeobecný parameter — typovú premennú, ten však musí byť označený aj v názve typu. To umožňuje definovať generické typy.

Príklad

data Maybe a = Just a | Nothing
data Either a b = Left a | Right b

Následne pri definovaní konkrétnej hodnoty, typová premenná bude nahradená za konkrétny typ:

priklad_1 :: Maybe Int
priklad_2 :: Either Int Char
priklad_3 :: Either (Maybe Int) [Bool]
priklad_4 :: ([(Maybe Char, Either Bool Char)], Int)

Typ môže byť definovaný aj rekurzívne:

data List a = Null | Cons a (List a)
-- Cons 1 (Cons 2 (Cons 3 Null)) ~~~~~ 1 : (2 : (3 : [])) ~~~~~ [1, 2, 3]

Úloha 3.1

Definujte typ pre binárny strom, kde každý list stromu môže obsahovať hodnotu ľubovoľného typu. Ten je ale rovnaký pre všetky listy.

data BTree a = …

Príklad

Príklad binárneho stromu
Obr. 1: Príklad binárneho stromu

myLittleTree = Branch (Branch (Leaf 1) (Branch (Leaf 2) (Leaf 3))) (Leaf 4)

Úloha 3.2

Definujte funkciu sumBTree pre výpočet súčtu hodnôt uložených v strome.

sumBTree :: BTree Integer -> Integer

Príklad

> sumBTree myLittleTree
10

Úloha 3.3

Definujte funkciu foldBtree, ktorá používa zadanú binárnu funkciu na výpočet hodnoty z údajov uložených v strome:

foldBTree :: (a -> a -> a) -> BTree a -> a

Príklad

> foldBTree (+) myLittleTree
10

Krok 4: Strom aritmetických výrazov

Úloha 4.1

Definujte dátové typy pre reprezentáciu stromu aritmetických výrazov s operátormi +, - *, / a číslami typu Double.

data Op = Add | Sub | Mul | Div
data Exp = ...

Príklad

Príklad stromu výrazu
Obr. 2: Príklad stromu výrazu

myExp = Exp Add (Exp Mul (Val 1) (Val 2)) (Exp Sub (Val 3) (Val 4))

Úloha 4.2

Definujte funkciu showexp, ktorá vytvori textovú reprezentáciu výrazu (so zátvorkami).

showexp :: Exp -> String

Príklad

> showexp myExp
"((1 * 2) + (3 - 4))"

Úloha 4.3

Definujte funkciu eval, ktorá vypočíta zadaný výraz.

eval :: Exp -> Double

Príklad

> eval myExp
1.0