Monads as containers/is

From HaskellWiki
Jump to: navigation, search

Mónað má hugsa sem klasa sem heldur utan um venjulegt gildi ásamt auka upplýsingum. Auka upplýsingarnar eru mismunandi fyrir hvern mónað. Fyrir Either eru auka upplýsingarnar eitt Boolean: annaðhvort Left eða Right.

"return" er smiður (constructor), svipaður og "new" í Java. Hann tekur venjulegt gildi, og skilar hlut sem inniheldur gildið. Return ætti heita encapsulate, vegna þess að hann pakkar gildi inní hlut, og skilar hlutnum.

return :: (Monad m) => a -> m a

Klasar hafa aðferðir. Mónaðar útfæra að lágmarki eina aðferð til viðbótar við smiðinn. Hún heitir bind. Í praxís er samt auðveldara að útfæra bind með tveimur aðferðum til viðbótar: fmap og join.

Map aðferðin þiggur fall. Map tekur gildið úr hlutnum, beitir fallinu á hlutinn, og pakkar útkomunni í nýjan hlut.

fmap :: (Monad m) => (a -> b) -> m a -> m b

Join aðferðin þiggur nested hlut, hlut sem inniheldur hlut sem inniheldu gildi; og sameinar í hlut sem inniheldur gildi.

join :: (Monad m) => m (m a) -> m a

Bind, ">>=", er samsett aðferð. Hún er svipuð og map, nema í stað þess að þiggja fall sem skilar gildi, þá þiggur hún fall sem skilar hlut.

(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

Fyrst, þá beitir hún fmap. Fmap skilar hlut sem innihaldur úttakið úr fallinu (a -> m b). En þar sem fallið (a -> m b) skilar hlut, en ekki bara gildi, þá skilar fmap hlut sem inniheldur hlut. En þá notar bind "join" til að sameina, eða fletja, hlutina.

(>>=) xs f = join (fmap f xs)

Auka upplýsingarnar sem mónaði heldur utan um eru mismunandi. Fyrir Lista, þá eru ekki beinlínis aukaupplýsingar, heldur fleiri gildi. Fmap sér um að beita falli á hvert stak listans, og pakka stökunum svo aftu í lista.

Stöðumónaðinn, State, geymir stakt gildi ásamt stöðu.

Svo er líka hægt að pakka gildi í hlut án þess að geyma neinar merkilegar aukaupplýsingar. Áhugaverðari er hlutur með aukaupplýsingar, til dæmis teljara sem hækkar í hvert sinn sem hlutur er tekinn í sundur og settur aftur saman (með bind eða fmap) -- án þess að geyma neitt merkilegt gildi. Til dæmis gæti gildið alltaf verið tóma tuplan (), án þess að breytast nokkurntímann. Köllum teljarann ástand heimsins, og þá erum við komin með IO () mónað. Mónað sem telur í hvert skipti sem umhverfinu er breytt (með I/O aðgerð).

Trikkið er að ef við ætlum að skrifa tvisvar sinnum í skrá með write, þá gæti Haskell tekið eftir því að seinni write skipunin notar ekkert gildi úr fyrri skipuninni. Haskell gæti freistast til að keyra skipanirnar samhliða, sem myndi enda með ruglingi. Í staðinn, þá látum við write skila hlut. Nánar tiltekið IO () hlut sem inniheldur teljarann "Ástand heimsins". Þá getum við passað að einungis ein write skipun keyri í einu, og í réttri röð, með því að segja að write skipun þurfi að vita "Ástand heimsins" áður en hún keyrir, og að þegar hún er búin, og ekki fyrr en hún er búin, þá skili hún nýju "Ástandi heimsins."