Kodutöö eesmärk on kirjutata olekuteisendusmonaadi laiendus, mis
lisaks tavalistele olekuteisendusmonaadi liidesele (vt.
Control.Monad.State
) realiseerib allkirjeldatud lisa
funktsionaalsuse
Kõigepealt tuleb defineerida uuele monaadile vastav tüübikonstruktor:
newtype StateMD s a = ...Tüübimuutujad
s
ja a
omavad standartset
tähendust: s
on oleku tüüp ning a
on
väärtuse tüüp.
Seejärel tuleb tüüp teha klasside Monad
ja
MonadState
instantsideks. Kuna klass MonadState
ei ole prelüüdis defineeritud, tuleb vastav teek importida:
import Control.Monad.StateKlass
MonadState
kasutab "funktsionaalseid sõltuvusi",
mis on Haskell 98 laiendus. Seetõttu tuleb kompileerimisel anda ghc-le
vajalikud lipud; lihtsaim viis selleks on lisada järgnev "pragma" oma
faili esimesse ritta:
{-# OPTIONS -fglasgow-exts #-}Järgnevalt kirjeldame lisafunktsionaalsust, mida realiseeritav monaad peab toetama:
Monad
olev meetod fail
tuleb
defineerida selliselt, et ei annaks täitmisaegset erindit (mis ta teeb
vaikimisi definitsiooni korral).
Monaadil tuleb realiseerida järgnev primitiivfunktsioon:
runStateMD :: StateMD s a -> s -> Either String (a, s)See funktsioon saab argumentidena monaadilise arvutuse ja algoleku ning väljastab
Left str
kui arvutus ebaõnnestus (ja viga
tekitati funtsiooni fail
väljakutsega argumendile
str
). Kui arvutus õnnestus, siis väljastatakse
Right (x,s')
, kus x
on lõppväärtus ning
s'
on lõppolek.
StateMD
peab koguma informatsiooni enda
primitiivoperatsioonide väljakutsete arvu kohta. Selleks tuleb
kirjutada funktsioon diagnostics
, millel on järgmine tüüp:
diagnostics :: StateMD s StringSee funktsioon peab loendama seni kasutatud bind (
>>=
) ja return operatsionide arvu (samuti teiste
primitiivsete funktsioonide arvu; sh. väljakutsutav
diagnostics
ise). Lisaks tuleb kirjutada funktsioon:
annotate :: String -> StateMD s a -> StateMD s amis lubab kasutajal annoteerida "alamarvutusi". Kõik primitiivfunktsioonid (
return
, bind
(>>=
), diagnostics
, get
,
put
, ) loadState
, saveState
)
ja kasutajaannoteeritud arvutused peavad olema
diagnostika väljundis.
Näide:
do return 3 >> return 4 return 5 diagnosticsväljastab
"[bind=3, diagnostics=1, return=3]"
.
Paneme tähele, et >>
on realiseeritud kasutades
>>=
ja seetõttu läheb kirja kui bind.
Näide:
do annotate "A" (return 3 >> return 4) return 5 diagnosticsväljastab
"[A=1, bind=3, diagnostics=1, return=3]"
.
StateMD
selle
instantsiks.
class MonadState s m => StoreState s m | m -> s where saveState :: m () loadState :: m ()Olekute salvestamine ja lugemine peab olema realiseeritud magasinina; so. oleku salvestamine paneb hetkeoleku magasini tippu ning lugemisel võetakse olek magasini ülemisest pesast. Kui
loadState
kutsutakse välja tühja situatsioonis kui magasin on tühi, siis monaadi
arvutus ebaõnnestub (nagu eelpool kirjeldatud).
Näide:
do i1 <- get ; saveState modify (*2) i2 <- get ; saveState modify (*2) i3 <- get ; loadState i4 <- get ; loadState i5 <- get return [i1, i2, i3, i4, i5]väljastab algoleku
1
korral listi [1,2,4,2,1]
.