Zoznamy

Ciele

  1. Precvičiť používanie porovnávania vzorov (pattern matching)
  2. Precvičiť prácu s funkciami vyššieho rádu pre prácu s zoznamami.
  3. Naučiť sa používať množinové abstrakcie (list comprehension).

Postup

Krok 1: Porovnávanie vzorov

V niektorých prípadoch je možné definovať funkciu viacerými rovnicami, kde namiesto názvov parametrov budú uvedené vzory. Pri výbere rovnice, ktorá sa použije skutočné hodnoty parametrov sa postupne porovnávajú so vzormi až kým sa nenájde taký vzor, ktorý je možné s hodnotou stotožniť. Tento prístup sa nazýva pattern matching.

isOne 1 = True
isOne n = False

Úloha 1.1

Definujte funkciu myReplicate s dvoma parametrami: číslom a ľubovoľnou hodnotou. Funkcia vytvorí zoznam opakovaním hodnoty.

myReplicate :: Int -> a -> [a]
myReplicate 4 8  == [8, 8, 8, 8]

Údajový typ zoznam má dva konštruktory:

  • [] — prázdny zoznam,
  • : — zoznam vzniknutý pridaním elementu do zoznamu.

Keďže to nie sú obyčajné funkcie, ale konštruktory dátovej štruktúry, je možné ich použiť vo vzoroch na ľavej strane rovníc definujúcich funkcie:

mySum :: [Integer] -> Integer
mySum []     = 0
mySum (x:xs) = x + mySum xs

Úloha 1.2

Definujte funkciu allOdd, ktorá vráti True, ak sú všetky prvky zoznamu nepárne, inak False.

allOdd :: [Integer] -> Bool

Vzory môžu byť aj zložitejšie a môžu obsahovať vnorené vzory.

Úloha 1.3

Definujte funkciu sumFirstTwo, ktorá vypočíta súčet prvých dvoch čísel v zozname. Ak zoznam má iba jeden prvok, potom ten bude výsledkom funkcie. Ak je zoznam prázdny, nech je výsledkom hodnota 0.

sumFirstTwo :: [Integer] -> Integer
sumFirstTwo [1, 5, 2] == 6
sumFirstTwo [8] == 8
sumFirstTwo [] == 0

Krok 2: Rôzne spôsoby spracovania zoznamov

Okrem zabudovaných funkcií, rekurzie a porovnávania vzorov, máme k dispozícii aj ďalšie technike práce s zoznamami. Často používané sú funkcie vyššieho rádu ako map, filter, foldr, alebo foldl.

Operácie nad zoznamami je možne vyjadriť aj pomocou špeciálneho skráteného zápisu — množinovej abstrakcie (list comprehension). Jej tvár je nasledovný: [ výraz | generátory, filtre ]

Príklad definície triedenia algoritmom quick sort pomocou množinovej abstrakcie:

qsort [] = []
qsort (x:xs) = qsort [y | y <- xs, y < x] ++ [x] ++ qsort [y | y <- xs, y >= x]

Úloha 2.1

Definujte funkciu doubleAll :: [Integer] -> [Integer], ktorá vynásobí dvomi každý prvok zoznamu. Použite tri spôsoby implementácie:

  • pomocou rekurzie,
  • pomocou funkcie vyššieho rádu,
  • pomocou množinovej abstrakcie.

Úloha 2.2

Implementujte funkciu divisors, ktorej výsledkom je zoznam deliteľov kladného celého čísla:

divisors :: Integer -> [Integer]
divisors 12 == [1, 2, 3, 4, 6, 12]

Pomocou funkcie divisors definujte funkciu isPrime, ktorá určí, či číslo je prvočíslom (prvočísla sú deliteľné len číslom 1 a samým sebou).

isPrime :: Integer -> Bool

Krok 3: Domáca úloha

Úloha 3.1

Definujte funkciu getValue, ktorej prvým argumentom je zoznam tovarov. Tie sú reprezentované dvojicou. Prvý prvok dvojice je názov výrobcu a druhý hodnota konkrétneho tovaru. Jednotlivý výrobca môže byť v zozname viackrát. Vašou úlohou je vypočítať výslednú sumu za všetky tovary od výrobcu, ktorý je určený druhým parametrom.

products :: [(String, Int)]
products = [("avia",1000), ("trabant",500), ("avia",400), ("tatra",600),
            ("trabant",200), ("avia",700)]
getValue :: [(String, Int)] -> String -> Int
getValue products "trabant" == 700

Poznámka

Vo funkcii použite funkcie vyššieho rádu ako sú map a filter. Okrem toho môžete použiť funkciu sum, ktorá vypočíta súčet prvkov zoznamu čísel.

Úloha 3.2

Definujte funkciu replace, ktorá nahradí slova v texte podľa zadaného zoznamu náhrad. Funkcia má nahradzovať len celé slová, nie ich časti. Môžete pritom použiť funkcie words a unwords.

replace :: [(String, String)] -> String -> String

replacements = [("fox", "cat"), ("he", "she"), ("dog", "crocodile")]
sentence = "The quick brown fox jumps over the lazy dog"
replace replacements sentence == "The quick brown cat jumps over the lazy crocodile"

Zdroje

  1. The Fibonacci sequence - HaskellWiki
  2. Foldr Foldl Foldl' - HaskellWiki