6. Haskelli praktikum
Näiteülesanded
dialoog
Kirjuta protseduur dialoog
, mis küsib kasutajalt nime ja tervitab teda sellega.
dialoog :: IO () dialoog = undefined
listi trükk
Kirjuta funktsioon, mis prindib talle argumendina antud arvude listi. Iga prinditav arv peab tulema eraldi reale. Näiteks:
> prindiArvud1 [1,66,99] 1 66 99
Kirjuta see funktsioon nii lihtrekursiooniga kui ka forM_
-abil.
prindiArvud1 :: [Int] -> IO () prindiArvud1 xs = undefined prindiArvud2 :: [Int] -> IO () prindiArvud2 xs = undefined
forM_
jaoks on vaja import Control.Monad
.
arvude sisetamine
Kirjuta protseduur, mis esmalt küsib kasutajalt arvu. Kui kasutaja sisestab mittearvu, tuleb veast teatada ning uuesti arvu küsida. Protseduur tagastab edukalt sisestatud arvu.
readMaybe :: Read a => String -> Maybe a readMaybe xs = f (readsPrec 0 xs) where f [(n,"")] = Just n f _ = Nothing loeArv :: IO Int loeArv = undefined
State
monaad
Olgu antud järgmine puu andmestruktuur ja funktsioon numberTree
, mis nummerdab puu lehed vasakul paremale:
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving (Show, Eq) puu1 = Branch (Branch (Leaf ()) (Leaf ())) (Leaf ()) puu2 = Branch puu1 puu1 numberTree :: Tree a -> Tree Int numberTree = snd . numberTree' 0 where numberTree' :: Int -> Tree a -> (Int, Tree Int) numberTree' n (Leaf _) = (n + 1, Leaf n) numberTree' n (Branch l r) = let (n', l') = numberTree' n l (n'', r') = numberTree' n' r in (n'', Branch l' r')
Kirjuta funktsioon numberTreeState
, mis teeb täpselt sama, kuid kasutab abifunktsioonis State
monaadi, et lihtsustada oleku liikumist arvutuste vahel:
numberTreeState :: Tree a -> Tree Int numberTreeState t = evalState (numberTreeState' t) 0 where numberTreeState' :: Tree a -> State Int (Tree Int) numberTreeState' t = undefined
State
monaadi jaoks on vaja import Control.Monad.State
.
Harjutusülesanded
kahe arvu summa
Kirjuta protseduur, mis küsib kasutajalt kaks arvu ning trükib nende summa.
summa2 :: IO () summa2 = undefined
arvude summa
Kirjuta protseduur, mis esmalt küsib arvu n, seejärel loeb n arvu ning lõpuks trükib viimati loetud n arvu summa. Proovige lahendada seda lihtrekursiooniga kui ka kasutades näiteks sequence
funktsiooni.
summaN1 :: IO () summaN1 = undefined summaN2 :: IO () summaN2 = undefined
arvu arvamise mäng
Implementeeri klassikaline mäng, mis valib juhusliku arvu (nt. randomRIO
-ga, moodulist System.Random
; installida stack install random
) nullist sajani ning kasutaja peab selle ära arvama. Kasutaja saab pakkuda arve ja programm ütleb, kas pakutud arv on suurem, võrdne või väiksem. Kui vastus on võrdne (s.t. pakutud arv on võrdne juhuslikult valitud arvuga) on mäng läbi ja trükitakse pakkumiste arv.
> m2ng Arva ära täisarv vahemikus nullist sajani! Sisesta number: 50 Ei! Minu number on suurem Sisesta number: 62 Ei! Minu number on väiksem Sisesta number: 61 Ära arvasid! Oligi 61. Pakkusid 3 korda.
m2ng :: IO () m2ng = undefined
Maybe
monaad
Olgu antud järgmine avaldispuude andmestruktuur:
data Expr = Const Int | Add Expr Expr | Div Expr Expr deriving (Show, Eq) expr1 = Div (Add (Const 3) (Const 1)) (Const 2) expr2 = Add (Const 1) (Div (Const 1) (Add (Const 1) (Const (-1))))
Kirjuta funktsioon, mis väärtustab avaldispuu või tagastab Nothing
kui selles tekib nulliga jagamine:
evalExpr :: Expr -> Maybe Int evalExpr e = undefined
Maybe
monaadi kasutamine lihtsustab lahendust oluliselt.
Ülesanded*
m2ngR
Implementeeri arvu äraarvamise mängu pöördversioon, kus kasutaja valib mõttes (juhusliku) arvu ja programm püüab seda ära arvata. Programm peaks ära tundma sohitegemise, kui kasutaja on vastanud enesele vasturääivalt.
Rekursiivne kataloogide läbimine
Kasutades funktsioone moodulist System.Directory
(https://hackage.haskell.org/package/directory-1.3.4.0/docs/System-Directory.html), implementeerige rekursiivne kataloogi suuruse arvutamise protseduur. Faili suuruse arvutamine teha ette antud funktsiooniga failiSuurus
. S.t kataloogi suurusena loeme selles olevate failide suuruste summa pluss alamkataloogide suurus.
import System.Directory import System.IO failiSuurus :: FilePath -> IO Integer failiSuurus path = withFile path ReadMode hFileSize suurusKataloog :: FilePath -> IO Integer suurusKataloog f = undefined