Haskell Hero
Interaktivní učebnice pro začínající Haskellisty
|
|
Typ složené funkceJednoduchý příklad 1
Jaký je typ funkce
Krabičkové znázornění této funkce naleznete v lekci Užitečné funkce. Pro zopakování: Co je to typ funkce? Je to zápis typů hodnot, které do funkce vstupují a typ hodnoty, na kterou se funkce vyhodnotí. To vše odděleno šipkami Typem složené funkce je tedy to, co do funkce na začátku vstupuje a co z ní na konci vystupuje. Nezajímá nás, jaký je typ hodnoty v mezivýsledku.
Jak je vidět z obrázku, do funkce odd . snd :: (a, Integer) -> Bool Jednoduchý příklad 2
Jaký je typ funkce
Funkce head [3,4,5] ~> 3
Pokud ale na ten samý seznam aplikujeme funkci (head . head) [3,4,5] ~> head (head [3,4,5]) ~> head 3 ~/>
Potřebovali bychom, aby první aplikace funkce (head . head) [[3,10,14], [8,4,13,15], []] ~> head (head [[3,10,14], [8,4,13,15], []]) ~> head [3,10,14] ~> 3
Jelikož funkci head . head :: [[a]] -> a Převádíme do pointwise
Pointwise je opačný zápis pointfree. V pointfree výrazu je lambda nahrazená operátory Pro převod z pointfree do pointwise nám budou stačit tři pravidla:
Složitější příklad
Napište nejobecnější typ funkce Možností jak tuto úlohu řešit je mnoho. Zde si ukážeme převod do pointwise tvaru a jeho následné otypování. Jako první musíme rozhodnout, zda máme výraz ozávorkovat ((.(,)) . (.)) . (,)nebo (.(,)) . ((.) . (,))Podle tabulky priorit a sdružování zjistíme, že (.) sdružuje zprava, to znamená, že správné ozávorkování je následující:
(.(,)) . ((.) . (,))A nyní již můžeme přistoupit k samotnému převodu do pointwise. Jak jsme při převodu do pointfree argumenty odebírali, zde je budeme přidávat. Aplikujeme tedy naši funkci na argument x.
\x -> ((.(,)) . ((.) . (,))) xVýraz upravíme podle definice (.) klasickým způsobem zleva doprava: (poznámka: značka ===>, která je zde dále použitá je námi definovaná značka pro zkrácení zápisu, která znamená toto převedeme na toto, není to haskellovský operátor)
\x -> ((.(,)) . ((.) . (,))) x
(--f--- . -----g-----) x
===>
\x -> (.(,)) (((.) . (,)) x)
-- f - (---- g ---- x)
Nyní můžeme využít znalosti toho, že (+5) 3 můžeme napsat jako 3 + 5.
\x -> (.(,)) (((.) . (,)) x)
(+ 5 ) (----- 3 -----)
===>
\x -> (((.) . (,)) x) . (,)
(----- 3 -----) + 5
Teď převedeme ((.) . (,)) x podle definice tečky.
\x -> (((.) . (,)) x) . (,)
( f . g ) x
===>
\x -> ((.) ((,) x)) . (,)
f ( g x)
Nyní jsme vyčerpali všechny možnosti a funkce stále není v pointwise tvaru. Přidáme tedy do aplikace nový obecný argument, například y.
\x y -> (((.) ((,) x)) . (,)) yA opět můžeme použít definici tečky.
\x y -> (((.) ((,) x)) . (,)) y
(----- f ----- . g ) y
===>
\x y -> ((.) ((,) x)) ((,) y)
----- f ----- ( g x)
V tomto momentě máme výraz ve tvaru ((+) 3) 5, který přepíšeme na 3 + 5
\x y -> ((.) ((,) x)) ((,) y)
((+) -- 3 --) -- 5 --
===>
\x y -> ((,) x) . ((,) y)
-- 3 -- + -- 5 --
Nyní jsme v situaci, kdy již zápis nemůžeme nijak upravit, ale stále to ještě není plně vyhodnotitelný výraz. Proto celý výraz aplikujeme na nový argument, který pojmenujeme například z.
\x y z -> (((,) x) . ((,) y)) zDále odstraníme tečku standardním způsobem.
\x y z -> (((,) x) . ((,) y)) z
(-- f -- . -- g --) x
===>
\x y z -> ((,) x) (((,) y) z)
-- f -- (-- g -- x)
Všechny tečky jsou odstraněny, nyní už jen převedeme zápis do infixu, aby byl přehlednější. Nejdříve do infixu převedeme podvýraz ((,) y) z.
\x y z -> ((,) x) (((,) y) z)
((+) 3) 5
===>
\x y z -> ((,) x) (y,z)
3+5
A následně i celý výraz.
\x y z -> ((,) x) (y,z)
((+) 3) - 5 -
===>
\x y z -> (x,(y,z))
3+ -5-
Co jsme získali?
O funkci v pointfree tvaru
Jaký je tedy typ funkce (.(,)) . (.) . (,) :: a -> b -> c -> (a,(b,c))Kdyby bylo cokoli nejasné, pište do diskuze. |