Ciele
- Naučiť sa používať interaktívny interpretátor GHCi.
- Naučiť sa definovať vlastné funkcie a používať ich.
- Oboznámiť sa s koncepciou typov v jazyku Haskell.
Postup
Krok 1: GHCi
Haskell je kompilovaný jazyk, ale existuje aj interaktívny interpretátor GHCi, ktorý umožňuje rýchlo skúšať zabudované aj vlastné funkcie. Po spustení GHCi je možné zadávať výrazy a sledovať ich výsledky.
Haskell podporuje bežné infixné operátory, napríklad:
1 + 2
2 * (5^2 - 4)
(4 <= 2) && (4 /= 2)
"hello" == "hello"
Aplikácia funkcie sa zapisuje bez zátvoriek okolo argumentov. Argumenty sú oddelené len medzerou. Napríklad:
max 4 2
sin (pi / 2)
sin pi / 2 == (sin pi) / 2
Úloha 1.1
Napíšte výraz, ktorý vypočíta dĺžku prepony pravouhlého trojuholníka s odvesnami dĺžky 3 a 4. Použite pritom funkciu sqrt
.
Krok 2: Vlastné funkcie
Vlastné funkcie sa píšu v súbore s príponou .hs
. Definícia funkcie má tvar názovFunkcie parametre = výraz
, napríklad:
add x y = x + y
Úloha 2.1
Vytvorte si súbor cvicenie.hs
a zapíšte doň definíciu funkcie add. Načítajte tento súbor do interaktívneho interpretátora pomocou príkazu :load cesta/k/súboru.hs
alebo pomocou tlačidla na otvorenie súboru vo WinGHCi. Skúste použiť funkciu add v interpretátore.
Úloha 2.2
Definujte funkciu hypotenuse, ktorá vypočíta dĺžku prepony pravouhlého trojuholníka na základe dĺžok odvesien.
Poznámka
Po zmene súboru je možné ho znovu načítať pomocou príkazu :r
alebo :reload
.
Podmienené vykonávanie je možné dosiahnuť pomocou tzv. strážcov (guards):
factorial n
| n == 1 = 1
| n >= 1 = n * factorial (n-1)
Poznámka
Telo funkcie musí byť odsadené keďže Haskell, podobne ako Python, používa odsadzovanie ako časť syntaxe.
Úloha 2.3
Definujte funkciu middleNumber, ktorá vráti stredné z troch zadaných čísel:
middleNumber :: Integer -> Integer -> Integer -> Integer
Príklady použitia:
middleNumber 5 3 8 == 5
middleNumber 1 1 1 == 1
Krok 3: Typy
Haskell má statickú typovú kontrolu, ale vo väčšine prípadov nie je nutné uvádzať typy explicitne. Prekladač dokáže automaticky odvodiť typy hodnôt a funkcií. Odvodený typ je možné pozrieť v GHCi pomocou špeciálneho príkazu :t
, napríklad:
:t 'a'
:t 5
:t not
:t sqrt
:t max
Úloha 3.1
Skontrolujte typy vašich funkcií hypotenuse
a factorial
.
Typ funkcie môžeme deklarovať ak explicitne, napríklad:
add :: Integer -> Integer -> Integer
add x y = x + y
Úloha 3.2
Definujte typ funkcie factorial
ako Int -> Int
a použite ju na výpočet faktoriálu čísla 21. Zmeňte typ na Integer -> Integer
a vyskúšajte to znovu.
Poznámka
Na konverziu medzi typmi Int
a Integer
je možné použiť funkcie fromInteger
a toInteger
.
Krok 4: Viac funkcií
Na priblížny výpočet odmocniny je možné použiť Newtonovú metódu. Jej podstata spočíva v postupnom spresňovaní aproximácie. Ak y je odhad hodnoty druhej odmocniny čísla x, tak lepší odhad dokážeme vypočítať ako priemer čísel y a x/y.
Takže v každom kroku výpočtu je možné overiť, či odhad je už dostatočne presný, a ak nie je, vypočítať presnejší. Na overenie nám stačí vypočítať mocninu odhadu y a porovnať ju s odmocňovaným číslom x. Ich rozdiel musí byť menší ako nejaká stanovená hranica, napríklad:
$$ \left| y^2 - x \right| < 0,001 $$
Úloha 4.1
Definujte funkciu newtonSqrt
pre výpočet druhej odmocniny pomocou Newtonovej metódy. Definujte si tiež pomocné funkcie
sqrtIter
pre rekurzívne spresňovanie aproximácie,improve
pre výpočet lepšej aproximácie,goodEnough
pre jej overenie.
Poznámka
Na výpočet absolútnej hodnoty čísla môžete použiť štandardnú funkciu abs
.
Krok 5: Domáca úloha
Úloha 5.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 5.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
- Simon Thompson: Haskell: the Craft of Functional Programming
- Harold Abelson, Gerald Jay Sussman: Structure and Interpretation of Computer Programs