Ciele
- Vyskúšať prácu s vlastnou dátovou štruktúrou.
- Naučiť sa definovať vlastné algebraické údajové typy a funkcie na prácu s nimi.
- 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
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
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