Motto: „Monáda je monoid v kategorii endofunktorů, v čem je problém?“
V Haskellu jsme se mohli setkat s monádami, aniž bychom si to uvědomili. Kromě IO monády (vstup a výstup) se jedná o tzv. monadické datové typy, které jsou instancí typové třídy Monad
. Příkladem může být obyčejný seznam. Ten implementuje monadické operátory >>
a >>=
a funkce return
a fail
takto:
instance Monad [] where
xs >>= f = concat (map f xs)
xs >> f = concat (map (\_ -> f) xs)
return x = [x]
fail _ = []
Kompletní seznam monadických datových typů lze nalézt v tutoriálu All About Monads. Rozdělení všech tříd programování s efekty v Haskellu je graficky znázorněno v článku na weblogu Nothing Personal.
Funktor nám umožňuje aplikovat funkce na hodnoty datových struktur (často se tato operace nazývá vynášení). Již známe fukci map
, která je funktorem na seznamech. Obecným funktorem je funkce fmap :: (Functor f) => (a -> b) -> f a -> f b
a umožňuje nám aplikovat funkce na datové stuktury, jež jsou instancí třídy Functor
.
Modul Control.Applicative obsahuje takzvané aplikativní funktory. Ty jsou užitečné pro používání funkcí, které jsou samy o sobě obsažené v datové struktuře. K tomu nám slouží operátor <*>
a funkce pure
. Všimněte si, že tento modul, podobně jako modul Control.Monad, obsahuje několik užitečných funkcí lift*
a taktéž, že operátor <$>
dělá totéž co funkce fmap
.
Ke generování pseudonáhodných čísel nám slouží modul System.Random, který obsahuje funkce pro manipulaci s tzv. generátory a se samotnými funkcemi, jež vracejí pseudonáhodné hodnoty podle zadaných parametrů. Protože jsou to funkce nedeterministické (vracejí pokaždé jinou hodnotu), jejich typ je součástí IO monády.
-- náhodné číslo > randomIO 154790042541763409 -- náhodné číslo ze zvoleného rozsahu > randomRIO (1, 100) 10 -- náhodné číslo ze zvoleného rozsahu přes výchozí generátor > getStdRandom $ randomR (1, 100) 66 -- deset náhodných znaků > getStdGen >>= print . take 10 . randomRs ('a', 'z') "kigmzhfsyi" -- deset náhodných znaků s čerstvým generátorem > newStdGen >>= print . take 10 . randomRs ('a', 'z') "utwdxycyyx" -- přepsání zabudovaného generátoru svým vlastním > setStdGen $ mkStdGen 123