9. Praktikum
Selles praktikumis võtame kokku Monaadide teema ja harjutame tüüpimispuude joonistamist lihtsalt tüübitud {$\lambda$}-arvutuses.
Monaadid Idrises
Kõik monaadid peavad olema funktorid. S.t. neil on funktsioon map.
interface Functor f where
map : (a -> b) -> f a -> f b
Et olla matemaatilises mõttes funktor, peavad kehtima vastavad võrdused. (Ei kontrollita.)
map id == id
map (f . g) == map f . map g
Intuitsioon: funktorid on konteinerid, mis ei interakteeru nende sisuga.
Lisaks peavad monaadid olema aplikatiivsed funktorid. Peame saama pure-ga konteinerisse väärtuseid panna. Ning, kui meil on konteiner funktsiooniga ja konteiner argumendiga, peame saama konteineri funktsiooni tulemusega.
interface Functor f => Applicative f where
pure : a -> f a
(<*>) : f (a -> b) -> f a -> f b
Peavad kehtima vastavad võrdused. (Ei kontrollita.)
pure id <*> v == v
pure (.) <*> u <*> v <*> w == u <*> (v <*> w)
pure f <*> pure x == pure (f x)
u <*> pure y == pure ($ y) <*> u
Monaad pole mitte ainult aplikatiivne funktor, vaid tal peab olema ka >>= operaator.
interface Applicative m => Monad m where
(>>=) : m a -> (a -> m b) -> m b
Peavad kehtima vastavad võrdused. (Ei kontrollita.)
pure a >>= k == k a
m >>= pure == m
m >>= (\x => k x >>= h) == (m >>= k) >>= h
Intuitsioon: järjestikku täidetavad arvutusmasinad.
Vaatame kiiresti veel ühte "monaadi": Future.
Future
Future on lihtne (ilma sõnumiteta) samaaegse arvutuse primitiiv. Tüüp data Future : Type -> Type on Funktor, Applicative ja Monad. Kasutamiseks tuleb importida System.Future.
Sellel tüübil on lisaks kaks funktsiooni: fork ja await. Hargnemine, mis käivitab samaaegse arvutuse: fork (f x) : Future a, kui (f x) : a. Vastuse ootamine: await y : a, kui y : Future a.
Näide:
h (f x) (g x)
v.s. samaaegne arvutus
let u = fork (f x) in
let v = fork (g x) in
h (await u) (await v)
Future on monaad:
await (do u <- fork (f x)
v <- fork (g x)
pure (h u v))
inetu?
Future on aplikatiivne funktor:
await (h <$> fork (f x) <*> fork (g x))
Pane tähele, et (<$>) === map
Kui funktsioonid tagastavad Future
h' <$> f' x <*> g' x
v.s. järjestikune kood
h (f x) (g x)
Ülesanded
Antud järgnev kood:
import System.Future
import System.Clock
time: Lazy a -> IO a
time v = do
c1 <- clockTime UTC
let r = v
c2 <- clockTime UTC
let d = timeDifference c2 c1
printLn d
pure r
longFun' : Int -> Int
longFun' x = if x>20000000 then 1 else longFun' (x+1)
one_long: () -> Int
one_long () = longFun' 0
two_long: () -> Int
two_long () = longFun' 0 + longFun' 0
ülesanne 1
Muuda longFun' funktsioonis olevat konstanti, et teie arvutis töötaks one_long arvutamine umbes 3 sekundit. Kasutage funktsiooni time.
ülesanne 2
Kasutades Future-eid, implementeeri kolm funktsiooni, mis "paralleliseerivad" two_long arvutust. Funktsioon paralet peaks kasutama let-e ja fork, await funktsioone -- tulemus peaks olema kiirem twolong-st. Funktsioon paramonad kasutagu do-süntaksit, fork, await funktsioone -- tulemus ei pruugi olla kiirem twolong-st. Funktsioon paraapp peaks kasutama <$>, <*>, fork ja await funktsioone -- tulemus peaks olema kiirem twolong-st.
paralet: () -> Int paralet () = ?q1 paramonad : () -> Int paramonad () = ?q2 paraapp : () -> Int paraapp () = ?q3
Tulemusi uurides peaksite saama aru, miks monaadid on "järjestikuse arvutamise mudel".
Miks paramonad arvutamist ei paralelliseerinud?
(See arusaamine peaks tekkima iseseisval uurimisel peale praktilist harjutamist. Loengus rääkisime, et see nii on, aga nüüd peaksite sellest tegelikult aru saama. Kui ei saa aru, küsige uuesti!)
Tüüpimispuud
Ülesanded
Joonistage järgnevad tüüpimispuud -- kui võimalik. Mis väärtused tuleb panna lünkadesse? Kui tüüpimispuu on võimatu, kirjeldage põhjust.
- {$ \{a : \alpha\} \vdash (\lambda x:\alpha. x)\, a :\, ? $}
- {$ \vdash (\lambda x:\alpha. x\,x)\,(\lambda x:\alpha. x\,x) :\, ? $}
- {$ \vdash (\lambda x:\alpha,\, y:\alpha\to\beta\to\gamma. (\lambda z:\alpha. y)\,x\,x) :\, ? $}
- {$ \vdash (\lambda x:\alpha,\, y:\beta, z:\alpha\to(\beta\to\alpha)\to(\beta\to\beta). z\,(\lambda w:\beta. x)\,y) :\, ? $}
- {$ \vdash \lambda x:\alpha, y:\alpha\to\beta. (\lambda f:(\alpha\to\beta)\to\alpha\to\beta. f)\, y\, x\, :\, ? $}