Monády

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.

Funktory a aplikativní funktory

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.

Generování pseudonáhodných čísel

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.

Příklady

-- 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

← IB016