Monoidy, zpracovávání argumentů příkazové řádky IB016 Seminář z funkcionálního programování Vladimír Štill, Martin Ukrop Fakulta informatiky, Masarykova univerzita Jaro 2016 IB016: Cvičení 05 Jaro 2016 1 / 18 Motivace: zpracovávání argumentů příkazové řádky Chtěli bychom zpracovat argumenty příkazové řádky jako nastavení programu. ./run -v -opt=o1 -q -opt=o2 -v (verbose) zapíná ladící výstupy -q (quiet) vypíná ladící výstupy program se vždy chová podle posledního přepínače -v/-q -opt umožňuje přidat programu libovolný textový argument výchozí nastavení je bez ladících výstupů a bez dalších argumentů IB016: Cvičení 05 Jaro 2016 2 / 18 Datový typ pro konfiguraci Nachystejme si na nastavení vhodný datový typ: data Config = Config { verbose :: Bool , options :: [String] } deriving (Eq, Show) IB016: Cvičení 05 Jaro 2016 3 / 18 Představa zpracování každý přepínač vlastně zodpovídá nějakému nastavení nedaly by se jednoduše „spojit“ nějakou vhodnou funkcí? -v -opt=o1 -q -opt=o2 IB016: Cvičení 05 Jaro 2016 4 / 18 Představa zpracování každý přepínač vlastně zodpovídá nějakému nastavení nedaly by se jednoduše „spojit“ nějakou vhodnou funkcí? -v -opt=o1 -q -opt=o2 Config { Config { Config { Config { verbose options verbose options = True = ["o1"] = False = ["o2"] } } } } IB016: Cvičení 05 Jaro 2016 4 / 18 Představa zpracování každý přepínač vlastně zodpovídá nějakému nastavení nedaly by se jednoduše „spojit“ nějakou vhodnou funkcí? -v -opt=o1 -q -opt=o2 Config { Config { Config { Config { verbose options verbose options = True = ["o1"] = False = ["o2"] } } } } Jaké vlastnosti má funkce ? IB016: Cvičení 05 Jaro 2016 4 / 18 Vlastnosti operace : uzavřenost Je množina všech platných konfigurací uzavřená na operaci ? IB016: Cvičení 05 Jaro 2016 5 / 18 Vlastnosti operace : uzavřenost Je množina všech platných konfigurací uzavřená na operaci ? Ano, protože: Operace má správný typ. :: Config -> Config -> Config Můžeme ji zadefinova tak, aby jejím výsledkem nikdy nebyla neplatná konfigurace. IB016: Cvičení 05 Jaro 2016 5 / 18 Vlastnosti operace : asociativita Je operace asociativní? -v -opt=o1 -q -opt=o2 IB016: Cvičení 05 Jaro 2016 6 / 18 Vlastnosti operace : asociativita Je operace asociativní? -v -opt=o1 -q -opt=o2 Ano, pořadí zpracování by nemělo ovlivnit výslednou konfiguraci. IB016: Cvičení 05 Jaro 2016 6 / 18 Vlastnosti operace : komutativita Je operace komutativní? -v -opt=o1 -q -opt=o2 IB016: Cvičení 05 Jaro 2016 7 / 18 Vlastnosti operace : komutativita Je operace komutativní? -v -opt=o1 -q -opt=o2 Ne, na pořadí záleží. argumenty -q -v produkují jinou konfiguraci než -v -q IB016: Cvičení 05 Jaro 2016 7 / 18 Vlastnosti operace : neutrální prvek Má operace neutrální prvek? N -v -opt=o1 -opt=o2 N IB016: Cvičení 05 Jaro 2016 8 / 18 Vlastnosti operace : neutrální prvek Má operace neutrální prvek? N -v -opt=o1 -opt=o2 N Ano, neutrálním prvkem by měla být výchozí konfigurace. defaultConfig :: Config defaultConfig = Config { verbose = NotSet , options = [] } IB016: Cvičení 05 Jaro 2016 8 / 18 Config: nová definice Upravíme tedy datový typ Config následovně: data Flag a = Set a | NotSet deriving (Eq, Show) data Config = Config { verbose :: Flag Bool , options :: [String] } deriving (Eq, Show) IB016: Cvičení 05 Jaro 2016 9 / 18 Monoidy: matematická definice Monoid1 je algebraická struktura. Je to grupoid (M; ·), tedy množina M s binární operací · : M × M → M, a těmito axiomy: Asociativita: ∀x, y, z ∈ M . (x · y) · z = x · (y · z) Neutrální prvek: ∃e ∈ M∀x ∈ M . x · e = e · x = x Někdy se uvádí i následující axiom plynoucí z definice binární operace grupoidu: ∀x, y ∈ M . x · y ∈ M 1 Definice převzata z https://cs.wikipedia.org/wiki/Monoid IB016: Cvičení 05 Jaro 2016 10 / 18 Typová třída Monoid class Monoid a where mempty :: a mappend :: a -> a -> a mconcat :: [a] -> a mconcat = foldr mappend mempty definováno v Data.Monoid <> je infixové synonymum pro mappend (v Data.Monoid) mnoho užitečných knihovních instancí opět několik pravidel, která musí platit levá identita: mempty <> x ≡ x pravá identita: x <> mempty ≡ x asociativita: x <> (y <> z) ≡ (x <> y) <> z IB016: Cvičení 05 Jaro 2016 11 / 18 Instance pro konfigurace Udělejme tedy instanci typu Config pro třídu Monoid: IB016: Cvičení 05 Jaro 2016 12 / 18 Instance pro konfigurace Udělejme tedy instanci typu Config pro třídu Monoid: instance Monoid Config where mempty = defaultConfig c1 `mappend` c2 = Config (verbose c1 `mappend` verbose c2) (options c1 `mappend` options c2) Teď ale potřebujeme ještě: instanci pro datový typ Flag instanci pro seznamy IB016: Cvičení 05 Jaro 2016 12 / 18 Instance pro Flag Jak chceme, aby se chovala instance pro Flag a? IB016: Cvičení 05 Jaro 2016 13 / 18 Instance pro Flag Jak chceme, aby se chovala instance pro Flag a? instance Monoid (Flag a) where mempty = NotSet _ `mappend` (Set x) = Set x x `mappend` NotSet = x IB016: Cvičení 05 Jaro 2016 13 / 18 Instance pro seznamy Jak chceme, aby se chovala instance pro seznamy? IB016: Cvičení 05 Jaro 2016 14 / 18 Instance pro seznamy Jak chceme, aby se chovala instance pro seznamy? instance Monoid [a] where mempty = [] x `mappend` y = x ++ y (je součástí knihovny) IB016: Cvičení 05 Jaro 2016 14 / 18 Všechno spolu A teď máme elegantní, rozšiřitelný systém parsující argumenty příkazové řádky :-}. ... který navyše využívá pěknou algebraickou teorii. IB016: Cvičení 05 Jaro 2016 15 / 18 Monoid: knihovní instance V knihovně je vícero instancí pro Monoid: [a] – instance stejná, jako jsme vytvořili my Last a – odpovídá našemu Flag a (je to vlastně instance pro Maybe a) First a – jako Flag a, jenom prioritu má první výskyt definované hodnoty (ne poslední) Any – Bool s operací || All – Bool s operací && Num a => (Product a) – numerická instance kolem operace násobení Num a => (Sum a) – numerická instance kolem sčítání . . . IB016: Cvičení 05 Jaro 2016 16 / 18 Typeclassopedia https://wiki.haskell.org/Typeclassopedia The goal of this document is to serve as a starting point for the student of Haskell wishing to gain a firm grasp of its standard type classes. The essentials of each type class are introduced, with examples, commentary, and extensive references for further reading. třídy, které už známe (Functor, Applicative, . . . ) třídy, které na nich staví (Monoid → Foldable) třídy jěště vyšší abstrakce (MonadTrans, Arrow) IB016: Cvičení 05 Jaro 2016 17 / 18 Úkol: rozšíření pro další volby Rozšiřte program o možnost následujících argumentů: -printer=lj4a nastaví tiskárnu, identifikovanou řetězcem. Vždy se použije první zadaná tiskárna. Předělejte příznak verbose tak, aby úrověn výstupů byla charakterizována přirozeným číslem. Použije se vždy maximální z nastavených hodnot, pokuď není použit přepínač -q. Tedy argumenty -v=1 -v=5 -v=2 nastaví level na 5 a argumenty -v=1 -q -v=6 na 0. Zkuste si v Typeclassopedii přečíst o typové třídě Foldable, která zobecňuje struktury, přes které se dá „foldovat“. IB016: Cvičení 05 Jaro 2016 18 / 18