Haskell Hero
Interaktivní učebnice pro začínající Haskellisty
|
Programujeme kalkulačkuCo budeme potřebovat?
Co je to kalkulačka? Je to zařízení, kterému zadáme výraz (například Naprogramujeme si tedy kalkulačku, která umí sčítat, odčítat a násobit. Abychom tak mohli učinit, budeme potřebovat dvě věci:
Definujeme vstupní výrazy
Do běžné kalkulačky zadáváme výrazy ve tvaru Vytvoříme tedy nový datový typ, který bude obsahovat všechna celá čísla. data Vyraz = Cislo IntegerTímto jsme definovali krabičku, ve které jsou hodnoty Cislo 1 , Cislo 2 , Cislo -5 , ...
K těmto číslům přidáme také výraz, který bude znázorňovat sčítání výrazů: data Vyraz = Cislo Integer | Plus Vyraz VyrazV této krabičce budou například následující výrazy: Plus (Cislo 2) (Cislo 5) Plus (Cislo 4) (Cislo 8) Plus (Cislo 2) (Plus (Cislo 2) (Cislo 3)) A podobně doplníme i výrazy znázorňující odčítání a násobení: data Vyraz = Cislo Integer | Plus Vyraz Vyraz | Minus Vyraz Vyraz | Krat Vyraz VyrazV této krabičce už bude i výraz znázorňující 5 + 3 * 2 . Zapíšeme jej následovně:
Plus (Cislo 5) (Krat (Cislo 3) (Cislo 2)) Definujeme vyhodnocující funkciNyní máme definovány výrazy a potřebujeme funkci, která nám například výraz Plus (Cislo 5) (Krat (Cislo 3) (Cislo 2))vyhodnotí na číslo 11 . Tak tedy začněme.
Začneme vyhodnocením výrazu vyhodnot :: Vyraz -> Integer vyhodnot (Cislo x) = xPozor na závorky! Funkce vyhodnot je unární, proto musíme výraz Cislo x ozávorkovat, aby byl brán jako jedna hodnota.
Dále musíme definovat vyhodnocení sčítacího výrazu. Chceme, aby se například výraz
Výraz
Do definice tedy můžeme doplnit klauzuli vyhodnot (Plus x y) = (vyhodnot x) + (vyhodnot y)A podobně zadefinujeme i odčítání a násobení: vyhodnot (Minus x y) = (vyhodnot x) - (vyhodnot y) vyhodnot (Krat x y) = (vyhodnot x) * (vyhodnot y) Celá definice tedy bude vypadat následovně: vyhodnot :: Vyraz -> Integer vyhodnot (Cislo x) = x vyhodnot (Plus x y) = (vyhodnot x) + (vyhodnot y) vyhodnot (Minus x y) = (vyhodnot x) - (vyhodnot y) vyhodnot (Krat x y) = (vyhodnot x) * (vyhodnot y) Vzorové vyhodnocení
Krok po kroku vyhodnotíme výraz vyhodnot (Plus (Cislo 5) (Krat (Cislo 3) (Cislo 2))) ~> (vyhodnot (Cislo 5)) + (vyhodnot (Krat (Cislo 3) (Cislo 2))) ~> 5 + (vyhodnot (Krat (Cislo 3) (Cislo 2))) ~> 5 + ((vyhodnot (Cislo 3)) * (vyhodnot (Cislo 2))) ~> 5 + ( 3 * (vyhodnot (Cislo 2))) ~> 5 + ( 3 * 2 ) ~> 5 + 6 ~> 11 Proč to děláme?Může vyvstat otázka — k čemu je to dobré? Vždyť Hugs umí sčítat i násobit sám od sebe, tak proč se zatěžovat definováním nového datového typu a funkce nad ním?
Zkusme si představit, že násobení na velkých číslech je mnohokrát výpočetně náročnější než sčítání. Například vyhodnocení výrazu Protože jsme si na začátku řekli, že násobení je na velkých číslech mnohonásobně náročnější než sčítání, vidíme, že výraz (3 * 5) + (3 * 6) se vyhodnotí rychleji než výraz 3 * (5 + 6). Chtěli bychom tedy výrazy ve tvaru x * (y + z) převést do tvaru (x * y) + (x * z) a pak teprve začít vyhodnocovat. Jak bude vypadat funkce, která bude takové zjednodušení provádět? zjednodus :: Vyraz -> Vyraz zjednodus (Krat x (Plus y z)) = Plus (Krat (zjednodus x) (zjednodus y)) (Krat (zjednodus x) (zjednodus z)) zjednodus _ = _K optimalizovanému vyhodnocení tedy nepoužijeme pouze funkci vyhodnot , ale složenou funkci (vyhodnot . zjednodus) .
|