Ciele
- Naučiť sa vytvárať vykonateľné programy.
- Oboznámiť sa s operáciami pre vstup a výstup.
- Oboznámiť sa s konceptom monád.
Postup
Krok 1: Spustiteľný program
Spustiteľný program v jazyku Haskell musí obsahovať funkciu main :: IO ()
.
Úloha 1.1
Vytvorte nový súbor hello.hs
, obsahujúci funkciu main
:
main :: IO ()
main = putStrLn "Hello world!"
Skompilujte tento program:
ghc hello.hs
Krok 2: Vstupné a výstupné akcie
Úloha 2.1
Upravte program na zobrazovanie histogramu tak, aby čítal zoznam čísel zo súboru, názov ktorého bude zadaný ako argument príkazového riadku.
Poznámka
Použite funkcie pre prácu so súbormi a funkciu getArgs. Potrebujete tiež pridať do kódu:
import System.Environment
Krok 3: Monády
Typ IO
je len jedným z monadických typov. Haskell však definuje viacero takýchto typov. Pre všetky z nich je možné používať operátory >>=
, >>
na spájanie operácií a funkciu return
na zabalenie hodnoty do monády. Pritom to, čo sa vykoná pri spájaní operácii pomocou >>=
je definované typom. Pre IO
je to sekvenčné vykonávanie akcií, ale napríklad pre zoznam ([]
), ktorý je tiež monádou, je to vykonanie ďalšej operácie na každom elemente z výsledku predchádzajúcej operácie a spojenie výsledkov do jedného zoznamu (xs >>= f = concat (map f xs)
).
generation = replicate 3
test1 = ["bunny"] >>= generation
test2 = ["bunny"] >>= generation >>= generation
Ďalším príkladom monády je typ Maybe. V jeho prípade operátor >>=
prepája viacero operácií vracajúcich Maybe
tak, že ak niektorá z nich vráti Nothing
, potom celá reťaz vráti Nothing
. Majme, napríklad, funkciu getTaxOwed
, ktorá vyhľadá veľkosť dane naprieč niekoľkých databáz pomocou funkcie lookup (kompletný kód s databázami).
getTaxOwed :: String -> Maybe Double
getTaxOwed name =
case lookup name phonebook of
(Just number) -> case lookup number governmentDatabase of
(Just registration) -> lookup registration taxDatabase
Nothing -> Nothing
Nothing -> Nothing
Úloha 3.1
Zjednodušte funkciu getTaxOwed
s využitím monadického operátora >>=
.
Použitie operátora >>=
v prípade typoc Maybe
a Either
umožňuje dosiahnuť efekt, podobný spracovávaniu výnimiek (exception handling). Prípadnú chybu nie je nutné ošetrovať v každom výraze kde môže vzniknuť, ale len na jednom mieste.
Krok 4: Zadanie
Spojme dva použitia monád pri riešení zadania — interakcie s hráčom v hre Míny. Použijeme monádu IO
pre realizáciu vstupu a výstupu, a monádu Either
pre ošetrovanie chýb.
Úloha 4.1
Implementujte modul Minesweeper.HumanSolver
z projektu.
Hlavná funkcia humanSolver
bude riešiť vstup a výstup. V prípade chybného vstupu tiež pomocou rekurzie zabezpečí opakované čítanie vstupu.
-- | Read a command from a user.
humanSolver :: Solver
humanSolver board = do
putStrLn "Please enter your choice: <O A1> for open, <M A1> for mark"
input <- getLine
...
O spracovanie vstupu od používateľa sa bude starať samostatná funkcia parseInput
. Ta dostane hraciu plochu (kvôli validácií ťahov) a reťazec zadaný používateľom. Jej výsledkom je buď zadaný ťah, alebo hlásenie o chybe.
parseInput :: Board -> String -> Either String Move
Samotná funkcia však iba normalizuje vstup a kontroluje, či nie je prázdny. O jednotlivé kroky spracovania sa budú starať pomocné funkcie:
normalizeInput :: String -> String
parseMove :: Board -> String -> Either String Move -- Expects nonempty normalized string
parseCommand :: Char -> Either String (Pos -> Move)
parsePosition :: String -> Either String Pos