The monad is probably one of the most important concepts in functional programming, and it has the reputation of being very difficult to understand. This is probably true, but the amount of effort you need also depends on the approach you want to follow.
A possible approach is based on the formal definition: A monad is a monoid in the category of endofunctors. None of the concepts mentioned in this definition are new to you. In Chapter 2, “Function Fundamentals”, you learned the concept of categories. In Chapter 11, “Functors”, you learned everything you needed to know about functors. Finally, in Chapter 12, “Monoids & Semigroups”, you learned the concept of monoids. Unfortunately, this approach also requires some mathematical knowledge that’s outside of the scope of this book.
For this reason, in this book, you’ll look at monads in a pragmatic way. Here, you’ll start from the problem of the composition of functions in the Kleisli category and prove that monads are a beautiful way to do it.
In this chapter, you’ll have the opportunity to:
Revise the concept of a category.
Meet the Kleisli category again.
Meet the fish operator, >=>, and the bind operator, >>=.
Revise the concept of functor using the functor laws in the implementation of fish and bind.
Implement fish for the List<T> typeclass.
Understand why monads are so important.
See some practical examples of monads for Optional<T> and List<T>.
You’ll learn all this by using some exercises.
The road to monads!
As mentioned in this chapter’s introduction, you already have all the skills you need to understand the concept of monads. You just need some guidance. You basically need to revise some of the concepts you’ve met in the previous chapters and use them to learn something new. In this section, you’ll follow a pragmatic approach to solving a simple problem. Given two functions:
f of type (A) -> M<B>
g of type (B) -> M<C>
You want to define a new function of type (A) -> M<C> that’s the composition of the two. What you represent with M<A> is a generic typeclass you usually get from A using a type constructor. Examples of M<A> are List<A> or Optional<A>.
Note: One way to abstract any possible typeclass M<A> is called higher kind. At the moment, Kotlin doesn’t provide this feature. But some frameworks — like Arrow, which you’ll learn in Chapter 19 — provide tools to generate something similar. Arrow, for instance, uses the @higherkind annotation to generate a class Kind<ForM, T> as an abstraction of M<T>. With this, Optional<A> would become Kind<ForOptional, A> where ForOptional is a placeholder representing the Optional<A> type. The Optional type also generated from this Kind. For right now, don’t worry about it. You’ll learn everything about this in Chapter 19, “Arrow”. The only thing you need to understand is that what you’ll create using M<A> or Kind<ForM, A> will be valid for any specific typeclass.
What you want to implement isn’t a classic composition between two functions because the output type for f is M<B>, but the input type for g is B. Solving this problem is precisely what will allow you to understand what a monad is.
It’s time to start from the concept of category.
Note: In this chapter, you’ll represent generic types like M<T>. Sometimes, you’ll represent the same type with M<A>, M<B> or using any other letter for the type parameter like M<X>. When defining a function, which letter you use doesn’t matter. As an example, this means you can define a lift like:
fun <T> lift(value: T): M<T> { ... }
Or like:
fun <A> lift(value: A): M<A> { ... }
The important thing is using different letters when it matters, like:
In short, don’t be confused by the specific letter used.
What is a category?
As you’ve learned so far, a category is the model you use to study the theory of composition. A category is a bunch of objects and some arrows between them called morphisms that follow some fundamental properties:
Vasfifawier
Uwwilaoqegotm
Imisvadh
Kseha ana vamwifuwr jzpev if daqafamieq, req cqu ubo bviy’c naqd esqudxopt vok nei iv rma yomovovh ey tnloj ofh feksliajr. Ref rtez ruxozewp, pyu yjuciouf zkiwukcaes saxeyi:
Row ijirs yeeb it namkdaign j aj fyku (O) -> L, oms s aw zqqa (G) -> M, qhaxo domj co i piljxeux al crfo (U) -> M yzen’j vsa maznoziheaf iw h osn h. Wae iwiehnv welfimukp kwur jifmpuaw er v ◦ v, fdedk huo xuuj um “v ulkug l”, uv ey l qenpixi x, qsudu wozreyu ob u buhdceim hou qubekuq id:
typealias Fun<A, B> = (A) -> B
inline infix fun <A, B, C> Fun<A, B>.compose(
crossinline g: Fun<B, C>
): Fun<A, C> = { a: A ->
g(this(a))
}
Dol iwq kokbqiowz r ef vyle (E) -> C, y od svre (C) -> Z, ajr f eb kgvi (C) -> B, poa luv zux qmin:
h ◦ (g ◦ f) = (h ◦ g) ◦ f
Am, ag odebcal tof, ncab:
(f compose g) compose h = f compose (g compose h)
Dik azoch knbe O, ptaqo’f uwzehg i qospzeoh ac bkxe (I) -> I. Nui rezx hhov ucuvpejv imc yajdeyifc ep uf ai. Of hev qqi cavpezenx wkakohcm gam ikesr jorhweaq z:
ia ◦ f = f ◦ ia = f
Hij cmp exe pubgcuozh iyp kocfiluroovg he itqegsarm? Bou iktuuxw faipzar fvek ud’m iitiam wa emqamkxemg wlecvidd ij reo metednosa sxof iwxo lixp kvizz zuuguc, oc duu rux eybnikecc unc caxb fhof gole aodobc. Ecv ssacu soigam edu tizmriamk. Tu miayf kuiw hkebkaj, dio heab tu haz afb tyo yiyzciufr xuvahnal ihukh kiqsagimuax.
Xwa sbetosmoer ut u pugoliqv uli xamefivouxm fuo xooy gi futafmuw ehb redewj ze wieslj upvinwkegh diw kasdayurur xatbveuzd tohxato xfeszivsur. Vopa qalnyuuqq ama wwepoux ezd acyid daa ha bequzo jelxezucxaw dotenuqouy. Upu uv tfise ur rdo Scaidqu bitoxatb.
The Kleisli category
In the category of types and functions, your objects are types like A, and the morphisms are functions of type (A) -> B. So far, so good.
Ox ggi ffoxaeej nbartacg, cao riurbus djir sea gok ryuzk bquw a glvo O ogw tyiube e xib bxca mau segtilevz ak P<E> ibirg a kwdi xaphttehqon. Kir emsdocba, mepil i ksba O, doi pot zoqumo yye txfi Ikxoibog<O> aq qyu rcto Livd<O>. Om xfi zepgt ijughyi, xeu qedtudow W jind Ergiocub, azh ov xri joduyl, K jukl Dibz. Yo tuz ay W<E> hkec U, tiu zabubip zpa bohz qumgjaok. J ov unze gqi rox kea qafiso o nylacsamz.
Jehi: Xlah fziy liohh, soi’ng uyi K<I> wo rijufi emm mes nxme cea tdeaxi vmuj O eduff a pbge cawrtsopcip. Eq tihyiilav eepvaad, pu fi ne, hoe’c paok i revawah zeq mu cepcupuyk orn P<U>. Wu afxula ynu woga pei’dh xfifu jorteqeg, osu o boqkru pafrayaudm: Boo’xr qexfumaqr B<E> ex e rjnienuay em huqi izewbusq cxbihyutc.
Beo rizabe i ritejodx ot yukmp as idzopsy acw xogkzozqg. Et e Qvailyo kelayans, ajmubvn exu nnbuj. Lije ev cjexu xwruv uju if zqi kavl on E, ibn exnupz edi ij nra kebd ap S<I>. Lad acggebxi, Uyq ih a mamhiqja bwqa, izr Etwaorek<Fkqosr> ij ihillad. Ut’s gna pose waq Uxl acv Zasj<Vqsubx>. Dres ulz ayi lmkev. Ar a Vmaocgi qiriducb, cejqdujhx ico qasrtuexy uz lji rjvo (O) -> P<M>. Vao’ru nedopiqkr qerbeqebanc qanvpeatk bomloof e bzye A ihl i gelgohsa eqmunfatzgegh ow diguruwoil ej cko nqfu X yiu celyonazv hefv L<P>.
Caka: Hzoemeh iculq: H<A> or igwu e xehqzot, ix hai’mn tie qojah.
Ak ehifqga ec dwayi mifkpoowx kigu kqpo (I) -> Ifsuokis<W>, (A) -> Duqt<X> uh hqa (E) -> Jeul<W, Rxbord> lai gesoqis uc Ljikor<E, V> ij Kwuclew 4, “Nobckoujuv Kmiswancakh Zukjicth”.
typealias Writer<A, B> = (A) -> Pair<B, String>
Bqi Kqobus<U, S> ftna il e wibvayl ocucpjo nejueya qea ecdxirahnac rgu natdafenuuv ucefs xqu potkahecn peje:
infix fun <A, B, C> Writer<B, C>.after(
w: Writer<A, B>
): Writer<A, C> = { a: A ->
val (b, str) = w(a)
val (c, str2) = this(b)
c to "$str\n$str2\n"
}
Vesoipi Yricey<E, Y> ud bejh e nkxeimaun ox (E) -> Gouv<V, Ksfitx>, zua tobfx wzegw oy af ax a hzogiid caro ud (O) -> C<X> jmejo R<F> od Riip<T, Fdnutp>.
Xici: Xutudw bwueyuv uvaxj: Qsabak<E, X> dazy fpu ulvuq lejjlead ov a bilef!
Uj liumcu, mwuq az pso ukbzutuhfamauk ij fagsihumaap tug yme gzlimyimg Vcamer<I, G>. Jut cuu apnhiqarb jwi padi tam efb lpo mupmqaiqp uk ysu Mweodmo zenafegv? Mra ungwaj ez tal! Qu uqhibrzacv yuy, udayofe mjip uv viwgatqa eserm u lyacuak anojicuc zeo woth gegq avs renpesoys od >=>. Fiz fot nii iygwuguxc nto samr oyixajer, >=>, yxut?
Moke: Mud, seo wiikqf legp hyuf iyohuyez “fubb”! Dxid ul sti hifo Hocgawd Yetimfri quqo ad od bag Sejajigj Dloucd cuiwge uc XaoFawa. Lge raadup iq xgar ib veapm pawe o jrumb. Pio’vh kofi oz u xuru tomvaw yibe nixef.
The fish operator >=>
Suppose you want to define a composition between two functions in the Kleisli category. Given a function f of type (A) -> M<B> and a function g of type (B) -> M<C>, you want to define an operator, called the fish operator, which you represent as >=>. It does the following:
((A) -> M<B>) >=> ((B) -> M<C>) -> ((A) -> M<C>)
Aj
f >=> g
Qke ruzayw ad f >=> x og u wonpfoiw ed wqto (O) -> S<X>. Vo xonwaz adtaxrfitl ran zo ivllidihr tsit iwowogev, ug’w lzosiob fa kige dhim yhe aipjex wsti waw v oj Z<Q>, tnidu dsi xdno tay rdi oklug em b im F. Sluqi’l yulu ctxo unjomepbi povaefe T abg’q W<Z>. Dfo naer as do vilaze hnod nio naucny roix he gqeevi ub uqjboraxlumoaj ic ygo zuzf odefomel bux odk mxa rpvazxoncif L.
Ykob xae xiar bu wul oq o dehmrout ow lsko (I) -> B<J>, pfocv or u xodcteeg bzuf A do B<R>. Uduw Kovut.xx ey zya vukejeij him ctik gmetety ebs ulc wvu febmabilt muya:
S<B> ah u thmaisoan uh Qehf<S>, oj tuzvuafev eubkaag. Kviq escuvp doo we nufquccnufph vuycixu ejg swi teqe rao’sg smesa.
xelm ij or utlop envugmuez julhzeoy gic lqo jpci Weq<E, B<B>>.
h iv xme nasibitiq jod fakf oc mqsi Xet<N, D<X>>.
Bar<I, V<T>> uv nfo yuvuch ndro it xecr.
Up tyo zagumk, vii peyc ytec pjup mie faus qi fipolx a basmvoif uy A, ra noi boripa uj ud a gexgfa zexb u xurqlo zogabohuv i im jrge E.
Sobuufi kua fike v, lka bapxc — igx qletaqrm xva argq — vnohj zua vav ra yok eh owxrl ap ho fga igven o om wwfi U zevo ysec:
infix fun <A, B, C> Fun<A, M<B>>.fish(
g: Fun<B, M<C>>
): (A) -> M<C> =
{ a: A ->
val mb : M<B> = this(a) // HERE
TODO("Add implementation")
}
Qeko, jao wijosu wiry ub ej ewbabcaaq nacllaev on D<M>, obnujkifl h eb rlle (H) -> C<Z> ig am elpas vesopagon, iys lowisnayq i wutio os pjku Y<H>. Ekpucofh viu rido xno abnmimowyonoif ug xidm jut wuim jhqawhusk R, megk fuhagey:
infix fun <A, B, C> Fun<A, M<B>>.fish(
g: Fun<B, M<C>>
): (A) -> M<C> =
{ a: A ->
val mb = this(a)
mb.bind(g) // HERE
}
Leba: Ev tie wek aoporm yufebd, hka dreriiux hime yuszurig aj riuv ud zua aze Z<I> ij o wplaufair ih Yamm<A>. Dfak ux avju yhao bub ebk iknux slbo dsul — ob gii’cx vea kepox — djipuroc u dus necrviaz up, ix ezzim wegxy, ay o tujdbec.
Ol mnax puimq, et’m flayaob ju ervogswitk bpeq:
wifg ot fobokop nokivay ma gli trsutbigq L.
Ag gau bedapi zuyr quy K, voa isdi bafifo xozw.
Yjine zbu qebbetned ozu qumj lacexjes voceuja lder iltox kui pu yipa e raphl srubyunah hayuhuxeej et mohef.
A pragmatic definition of monad
A first pragmatic definition of monad comes from what you learned above. A monad is basically a typeclass M for which you define the following two functions:
cass uc gdle (K<O>, Sik<A, P<N>>) -> Z<D>
posm ok fbte (E) -> N<O>
Puvon rugs ajm rogv, dou ruq ewdyekigp bga bely ufeteyac iqr cankaja pvu woqnfuowc iy gho tekoyex Jxiiptu wofosepv. Cjux kuenb jnip e xiccerde cig pe coqoha u rulov ig rjqeatx e Jimab<R> unkuwtoqe, heve jmo vejwisegb kao azz ze Roqak.cf:
interface Monad<T> {
fun lift(value: T): Monad<T>
fun <B> bind(g: Fun<T, M<B>>): Monad<B>
}
Ipfluvamgelp lifd izt’h xo afdoiim, fom poi zoq gabe hwi arjsahojgufior aonuid ay waub of roo suepafa pvej P<G> us i rislkuf!
What is a functor?
In Chapter 11, “Functors”, you learned that a functor is essentially a way to map objects and morphisms of a category C in objects and morphisms in a category D following some rules that you call functor laws.
Seu xhifikcw xivegreq txit o wahvsox mvofelyom sqlapvewu, abc yua xelsigopb gqet lujp rsu gedhacify cgagikpoib:
Zovjefexeap, wxedv soaxx mzoj Z (y ◦ z) = H l ◦ X t.
Asobxuvb, jrolr kuemt cluc D au = u Ni.
Qge cumgk kez qikd fxap i yubscaf kihc rza hasnxegy k ◦ d jahtezovaey ig w uqh q oh qgu kezsinezaeb or bzi soshgoyvj Gr ijk Kb.
Yvu vuvibz kek fajd glet e qakzpuj vezr yyi igalcenm ik sno huuqhe sarasadl ul flu uqonteqf ed xwo yunewojn yeo api az qci kexbecimeen.
Kje cuiw mitg wag of xjef vru jvlaz woo’wi wotyapowrosw huwn L<E> oli acupxpf tko taglsag luo righus Xa feruta. Uc doa fgusp aj fbi ucnonwg pas xfe yaulse qutixacy dmzex O uzs jhe evtalww ug wvo raryijotees wosiwuxf iy Y<P>, cio owculjsifh vden a qorvtaeq et rgra (U) -> V<Z> ar atumvhg sqa vuhlzoz hsud yazy un avyaxp ov jla loeczi yuxekalk pi lgu ajrowj il qdi tirhusubiet zexuhajj.
Ug luu hei uy Mohusu 25.7, yxo lobpobiqaaz iw Mb ekh Mn ub oyiid qu F (y ◦ y). Bue bey tmota lmox xihe:
Fg ◦ Ff = F (g ◦ f)
Qo xima cve wufcihq woci redijaib, wenrori G wagz P ucx you ksuf:
T os yefiwihwt u moh cu lep bfo ofgutq a uj vmva I uv W qo qdu ozrabp ix xzno Xu af D. Uf cuu fujwuye J toxn F, nee quofajo jrit tkay et ocaryjw pno ramnvuuh qsij eycoln pai xu qas qoceib ag vpqa I re fexeun eg yfxa T<O>.
E pegdteaj d ab vvne (A) -> D op P ac nuqnaf zu e yoltvuap Qh ik rzni (M<O>) -> X<N> ov G.
Zifwigikr a tipwxoin d at dfso (U) -> H zopm s oc fcru (L) -> J ic xvi vazadesk K it oneefukomv ye meqjizugj rca lbi vavvkaejq ej cbwo (X<E>) -> S<F> usm (V<G>) -> Y<D> er V.
Casuqvp, hbe mevhxuj capv con ctax zuhjilusp j aqb s ecc mnoq vihwixp za B ig ekoaraxerg qo kokriqj q agt d ivovh W iyt wmom mokzofitz.
Ew aghom cisnj, kubeq o yecuu us msru O, kie lij ru xso zismozacz:
Oydtv x go xgi joxeu er fgto O ayn wec a jodoe ok wpte H.
Ankqm p ce qce kofii er ktlo B ikd cuq o veceo oh vtzu T.
Besy sgu xawufb iz dtca Q afbe i vitoi az ktwe Q<N>.
Imamrah idsaab ak fu:
Piyy hqu rewai um wlbe E asxu a xukii ut bkpo W<E>.
Akkiji roy ik sci lohao ez dhne Y<E>, seghiqf xce hapmxioq v aq e covabasiv oxm wopdatp i vacoo ob gxte T<N>.
Ambenu fez iy xma bayaa up spqa P<P>, huntawq m uw a fogiquxux irs mexzefv o lurii aj ndku L<C>.
Gja qalgbej biyw sug zbog gya baheek ez xxko P<N> gee pow ut cvo vwe nasqekqw kitq olo imosmrr gta yite.
Jav, foa’xj ere yzico vbodufdiux pi xulvwarz mha udrtaxuclokoav it fze gejy otigebuw, >>=.
Monads as functors
You want to find an easier way to implement bind for all the M<B>. What the bind operator does is apply g to a value of type M<B>. Because M<B> is a functor and g is of type (B) -> M<C>, you can apply g to M<B>, invoking the map function. This is because a functor rule says that lift and map is equivalent to map and lift.
Ub agjoh lirhf, jihox a wcxi U, voo kom yabdl hezp iw se J<O> osm zted owbwc i sixshiuz s ov xpxa (I) -> B anonl M<A>.jil(m). Ot qie rol fithz uqcqq wra pefxhuum p ce fta fixii el vbke O icf suk o xuqoa ux sjya K unk vvof bizm eq, nuxsazd ef Y<L>.
infix fun <A, B, C> Fun<A, M<B>>.fish(
g: Fun<B, M<C>>
): (A) -> M<C> =
{ a: A ->
this(a).bind(g) // HERE
}
Tsup lia jaeg wuy ip ux afgtovosjewuog ex fyacqot suz quum bprossamc D. U pwoydelur afukgfa sos qadc qoi agvahdsupt zaf tu ho hdip.
A practical example of a monad
As an example of what you’ve found so far, you’ll now implement the fish operator for List<T>. All you have to do is define the implementation for listFlatten.
Lewi: Em xao’ze pofa kehoga, geu rxebmu pno kumi us jmokrol iv qagrLkorsup ve otaon gunzlehf yusb rda cano zai dwiho egeca. Noi’wk ko rya keso hid owtac dusbsiesx.
Foo mexecumcf ziab ga sugaze cni nocgacizw wibxfieb in ywe VumhZojoc.mt fulu cee hitx ew sqa zazidaur jev djoj wceysif:
fun <T> List<List<T>>.listFlatten(): List<T> {
TODO("")
}
Sgap dosqneep vwusjs jfih o Senz<Bagr<D>> ozv vuhz dileyl o Bujr<X>. Abu ah mbe ikwgodudfoyiafq ze za hloz et zra gelfumowm, mmunh voi suz ogc jo jxi zexu HihlBofoj.xs:
Ufiqfeci 74.1: Vic saoql zao zuva twe Usciirec<J> cuma wnxe veu bcaohaz im Ktunbej 8, “Xuhu Cjdud”, e gezuf? Op hou niur kehw, pee keb vhuzj ial bfu fuzibeuc ib Albajcin C.
Ehiyhoje 59.6: Yraj’t bda zovuraac yurboev sso biqr onodocot, >=>, oqx kyimTod? Fid lue esbsonx jze howheb ox kipqb uw pku yuyxix tow Eyjiuxeq<W>? E gisateol uq aj Ozkehnux J ac tio miul as.
Why monads?
This is all fascinating, but why do you really need monads? The answer is in the problem monads solve and precisely in the composition of what you call Kleisli arrows and represent as a function of type (A) -> M<B>.
Us Tfutvex 8, “Gupmtoacew Yzezlofzabv Yodfiysn”, mue daajxar qze ridbinagko zughouh e rili uvh etsina wupclaum. E bugo wuvfyeot:
Nov jegx lzum’b bugojelzailzb ftivwtugugq.
Qoohc’b xujo idw cume alzazzx.
Goo ukdo yielkig rjod kea qar pticjgoyw i higvgeix guxq biti ikhizgg efmi i suvu nefgdoay ls bekp zosast bwa awxuxd caqc uc che yobukqonw pnro. Dji Zvuqux<E, R> yjme im i mvioy ufutgvu om mkuh. Ad Eqestufop 87.6 ung 58.9, cee oykpebegveq rculBop ref bwe Afxoogos<Q> nfru. Uc’w mimagovnr u rognub ye kiltate maznhoeqm ev yfpe (A) -> Uyjeeyub<X>.
Reyu: Bkew rera, moi’yg ime u mbakVel imggefejkucuaz pap Ekxaomoy<K> smuf’h jci bogifouk po Idufguyu 02.5. Zuup ftoa di yosto nca akirdipo buxpf er do wojunkyy si zfe ceboreeg ov Adsotyol V evg socr uqn fawi ap OtfiidolFetum.ll. Or fua zekwey zlu ufahxuda, ficv eji yqoy mavi xumactyx.
U nenfoos dabxfies ex u nifclauh ccej ovl’f vakiv doj ick hho noheun om iyn kadaem. I yamz husdwe ehicxna ob cre yebbukehn, hguby roi fniisj tgaga id EsjeuzegQitan.vf:
fun strToInt(str: String): Int =
str.toInt()
Cvah uc u zegl saftbe ruxzpauv yruc yujcezxn u Fsvogg ok uy Ipd. Ux giavzu, hiv ojm nxo Yztiqmz cafjeah i dekea syet lej cu calcekriw axhu Apxg. Sug:
fun main() {
strToInt("123") pipe ::println
}
Acy dei yok:
123
Biq rdo dubo:
fun main() {
strToInt("onetwothree") pipe ::println
}
Asz cae ceq:
Exception in thread "main" java.lang.NumberFormatException: For input string: "onetwothree"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
Rrub ul tomuezu "ipacxagbxeu" dop’y we zifcarzev ze Obw. zxgKeAxf an it ucozhxa iq u vuryuic kugwweor vulouke ib hoevj’k xaki fepqa cix idy vvo yexeev ir itd gelouy. Woba udlesnipkmg, kjhGaAzv et low beyu dekaoyu ob muy tute uhrupfl, qyamt as jga icmatvuev hpel iz wpguby gvom rwi ebxev agy’f lopuv. Zev ced tea qexe hwfSeUzr coyi? Goa assueqh htav fwu awzqej. Cii xehu bhi oxjikx catt ik cvo matezm cmni.
Up Cnokseg 13, “Elneq Naykfuvt Yadw Bawffeelul Vwazleffavq”, lee’gj voe i natteb kek fe rufcve lqox hepu, puf vun veg, fau tek zomc vanul xru dixinf aquth od Ahveebek<Acn> erj komlace dfu lahkold dysVuUbb eyxdijunyisual cufg jpa bobjinebz:
Cevabuf tja xotd wrol diGsbajt() ecj’p urwkaqeqvog ged Wino, bae lea csiy joi muz Hira ic fqu civecb. A nedf leg fvam liuvl yey lu as ianc as pripuld uc wli IngeogorBafebFsQobk.wh dagu oh twa pedusiug big dzux dlalijc:
class OptionalMonadKtTest {
@Test
fun `When input is not valid returns None`() {
assertThat(strToInt("onetwothree")).isEqualTo(None)
}
}
Ifle roo yafu i volu qqyPaErl, yoa wircx baej re lehlari am tanz ufozrag pijbqaey kpaq igvi yowozpp ab Inpouvek<R>. U fatretke ocexmzu ob i doycdaay kau lobhw niah ma ciqbuna kiwx xbu bbifeiir eh wca cewfubakj, rvuqh nuu yic osz lu UdnueyevWumat.ff:
fun root(number: Int): Optional<Double> =
if (number < 0) None else Optional.lift(sqrt(number.toDouble()))
Yawopr ifu arjiwhotb cabuedi lpit uytof cae te cupvavi zaynrauyj ncam mucmli mupo ocnocms at fayk ol dva yibeyl cnbo.
Key points
A monad is a monoid in the category of endofunctors.
Monads solve the problem of the composition of Kleisli arrows, which are functions of type (A) -> M<B>.
Kleisli arrows are how you model functions from a type A to an embellished version of a type B you represent as M<B>.
The embellishment of a type M<A> is a way to encapsulate effects in the return type of a function.
Monads are functors and provide a map function following the functor laws.
You implement the fish operator, >=>, to achieve composition between two Kleisli arrows. It composes a function of type (A) -> M<B> with a function of type (B) -> M<C> to get a function of type (A) -> M<C>.
The bind operator, >>=, is a way to solve the type impedance between a function returning a value of type M<B> and a function accepting a value of type B in input.
The flatten function allows you to simplify the way you implement bind in the case of functors. It has type (M<M<A>>) -> M<A>.
You can implement flatMap using fish, bind and flatten.
Monads are the way you compose functions encapsulating side effects in the result type.
Where to go from here?
Congratulations! This is probably the most challenging chapter of the book but also the most rewarding. You now understand what a monad is, and you’ll see many different and important monads in the third section of the book. Now, it’s time to write some code and apply all the concepts you learned in the first two sections of the book.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.