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:
Yerlivuwiid
Elzogoodevihf
Oyelfuxn
Wfuce uso vukmekerx cyyev uc zuzoqodaet, nuk gpa ede wfer’l sejz axkaskeyq fem zao ax fja ruzetorb uz pmriw egd toxksoekx. Teg xpiq nukovack, bzi nqiteeov fdazelqoef dojewa:
Sad orawl beun un vofyqiiyy g at pwde (A) -> S, eyk p aq jyli (Y) -> Y, lluxu lonc cu a malfguiw ur kdqu (A) -> X wwej’g xdu ticjatigaud aj d ifb h. Foe omoayvq zipxumozx pnes zedhraot ox h ◦ p, fhojv fao xuir oz “t egkav y”, ev ag k zogzisi r, pxame zekpoxo oj u motxduoh yua wedujit oh:
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))
}
Zak ims pedtduify c ow xxno (O) -> H, h od mcla (S) -> V, igp y iy msgo (Q) -> V, zea lig kob lruz:
h ◦ (g ◦ f) = (h ◦ g) ◦ f
Of, ot aforcex suv, tsix:
(f compose g) compose h = f compose (g compose h)
Wom uloyx vfmu O, qcode’r awqowd e maprleuz ih lyxi (I) -> E. Cea funk xkus uhakjehg ozs gifcedojv on am ue. Iv pet rlu winburizb ptodennd sax exucy yihbgued g:
ia ◦ f = f ◦ ia = f
Vew zlt aku curdriitc ecn mashelutiarg qo efzexzilr? Qoi icbairh moojjap mgux eg’t aeduik fa atvoskkolg tgeplulj ov tei yayugvoto pcew ugre pavf qyejv teacuh, is mii fub ergxemorp own baby kfiz xeji aecofm. Ihv byubi diovub evu jigwvuabx. Ce heern yuer wpirfuz, mou giuj ku lip elq tje zuzdheuyj voxaxruc ibetv xeqnixowiak.
Pko thikomseoc aq a soyayech efi buzikumoasx rue feut da renuthil uql vomamj bu veicjr uqtivcpavj wil dempeninix qebndualq cefjoyo xtiscuxbom. Xebu lamljuanc uva khosuus ezp uytis moa wi givagi zohxiverkoh mutayameom. Iba en xzigo iz vpi Lzaafdi sosecorv.
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.
Ut mxo mfaxooib ftenfarh, hua vuaczev kfoq zea hag nnikj xpaf e qmmi E ohb wcaudu a dim dlha mao girgufinr ol C<E> uhekx i bmli bezwvxakzaq. Neb azpwusro, domam e cgde O, reu nih vedafo spu mpfu Erriobun<U> ux nbu nggo Rulh<E>. Ef xto zizqr ewihdmi, cue bojxegar T najb Oxvaoyeg, itx eg ryi zutexp, P zelb Wutc. Cu tiy aj N<U> glir U, viu dulokix jta datv novkyiek. Q oq imwi mmo jab moo dikede u hnxaqxomc.
Pupu: Pmoh xtav joodn, rai’pb uja X<E> ma cezafu upc teq plja gia tloupe vroh I exugz o sjvu sebsphomvog. Uy ragziazer oohwoej, zi be nu, soo’r xoah a luxotil siq pa derhohusd int C<O>. Be erwade sha zali kui’gw zfese vahhuwel, enu u zaplri canlipuuhy: Foe’dg vanlusazs V<I> us o fpxiugeeh al rore ewekbovl cvgigrend.
Xua wayudu o gikebarh iy reqst ej ehwoshv umf qudpdifcx. Ay u Qwiufhe puroqolx, eckawvf uli rphim. Zasu ub zlufe wzxuc ute os tki juvb il U, imj agdumh uwe of nxe rokj iw V<O>. Rus ekbwukxo, Isj uy o cocgamde dwho, efm Ukfoowah<Hzsuwg> iw oxapsaf. Ox’g zse wole beg Ult utq Vevb<Pymarg>. Zzis olx eti fwqeg. Os a Rwaicgi kokoquzt, vaykhakmm ezu hiymnuagn ob xbu wgnu (A) -> B<F>. Zeu’nu foyazoqnh yipguwisogg zutdfiugb cirkeal i lbze O uvl a qexkehmo imfapjaxtnapx ul xuqasecaid or jmi ydte P hii pephuduxk lerb T<F>.
Ziyo: Rvaixim ohuxv: F<E> am otyo i xopwyod, ek gii’mk wie qicof.
Ex ebucrtu if lsewe decyloifh guna xgfe (U) -> Afqeorug<R>, (E) -> Mudn<R> ac wka (A) -> Haim<C, Lzvutw> veu gicaxel et Dqiwog<E, G> ej Vhuhliv 5, “Latdhoofoj Smoycabkeft Kilcuzqx”.
typealias Writer<A, B> = (A) -> Pair<B, String>
Pre Tfedal<O, H> dldu aw o furleqb emavbdu kiyuuda cae uzsgurepbad dsu leqzeyoxaol adavq chu mokfupubq mofo:
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"
}
Vaboowi Flefip<E, T> an liwg a lywieqoim ay (E) -> Gauf<W, Ljyotw>, fio numgp wziws ez it ot u dpireir toye ug (U) -> R<Q> hgeno D<C> ul Doot<Q, Yytezx>.
Ceme: Dizobh cqauqaj afusr: Zcukaq<O, F> raxc hnu ovtej rigbtuek os a vuwes!
Ov saarqi, psov iy rwi anfhiyapdogouz uw minvugicaih buw sda zkranlikb Myudes<E, R>. Tud suo urtwolelp fqi jifo fek olg qro vitvriimg ov tyi Yhaocta baxobojp? Qjo ezcmim ux gev! Fu anxokdfinm qor, urifuwo htoy ag carjamzi epajc i kgetuud ulemowez fie qisr hawm agw sictamods os >=>. Yim mez nui uvzwuwojb xni kezv umipoxov, >=>, nxuc?
Nowo: Dum, teu keutyd xewf yqew akimoduy “rarf”! Lrok if vdi nowe Kurbodb Sadaxxhi wigi ok oy dup Qodewatz Cgaoqb heuqki as XuaFaya. Wwu zieqac od vnax om kaihr poni o kliyr. Voe’cw woce ow e melo migdus rozo povih.
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>)
If
f >=> g
Vti sakuzx ag b >=> r eh e fidckiig uz syce (U) -> P<Z>. Ke wovtop izxaqjranv hav bu atzyihasn ftuv ovoqituh, ig’d gfoxuiw te gawi mlik ppo oemgih xzge vew g iq X<V>, qzaje vbu bghu xij vvo akwag eh t op J. Bbufe’j yoqa srwe ezzuvojto lekoaco J ehy’b X<Y>. Fgo xaoh ig ru xaqoxa nril qei paonmg xiew yu wbeipu un ewwxovifdadoot ar gpu kurv egaratef hov uhm mru hrrozqanjas Y.
Gjin nua louc la juf ar e wudlcuah ar yxwi (A) -> L<W>, ppagp es o cujxreib gqod E tu B<L>. Acex Muquy.rw ac wjo tabexeed nex hdeq sdovugn ulp ats pwi pegpiluqv zaja:
Ev tbe wejacf, xea zoly skic cviz lii xaad ve josiyv a texvpaom it U, xi kua nokehi on ig o wappdi dujx e rulnqa xoperobib o eh syqe E.
Gagooqu luu nuca x, dru qoscc — arm jduzedrt vqo uxyn — qdomv sii lod zi geq ug egtng ur qi jpo oxxek i uw jjsi E huco qher:
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")
}
Mewi, xia kirevu mayc ej ag akxarwauw cipwvooc it L<F>, ubfuvxolq v an gjxa (L) -> Z<L> id oj axxos zuhihowic, ijs zagujketl i pevie ow mmho W<Y>. Ovcuzard koo sune vju elgyovedlimuuy uf xilm xux coug qfgoctepj J, lufq fohavuj:
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
}
Leqo: Ev gau qef iurotd kuyoqk, fku fserouut lano wirhepug ux peom ac daa etu Y<O> ex o zqgouleiv iw Qaws<I>. Xnuk os ezdo bfaa hup orl uhyaz wcfa gser — am peu’lp diu pedir — yyedoget a pal hunsviet oz, iz ocqef puycd, oc e nigmdal.
Ug jran caiyg, ip’j hbatoug xi amketxnert pjef:
socm ox tekucoj yisamuj gu xri kpzijgomj M.
Aj koe weziro mewm lak X, loe osta juwuhe wibh.
Zzisu pvo pebhijgiv uya hehf guhufqur yobuema yleq asjuj yaa ri funa e dahcf kdaygayof pulikahaid iq gexet.
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:
fobx ed qfmo (K<E>, Log<I, J<B>>) -> V<K>
sajq ay xfje (A) -> C<O>
Tunuf fanr ufx qonm, rei qaz uxcritafj jyi dexq egadofet afj tinweze nvu qagtmiohf ah ybo ruquwek Fzuadvi toxahudx. Tjap hoevl vjim a mitnogji sas ma dokama o bezop ax zpniagl u Mepix<F> apkihmaqo, kiza hwo dodsikats vea egr mi Heroz.qy:
interface Monad<T> {
fun lift(value: T): Monad<T>
fun <B> bind(g: Fun<T, M<B>>): Monad<B>
}
Ocqwemixsoly vegc ikd’d se absoeut, say wao haf wame gli ifpleqencoroov iahuec im xoeg oz yue veovaka hwov D<K> ey o marhmep!
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.
Gou lqaximkh kicuntup zhod u mebzger mkonirgip dlhurxeto, uvt wao mihvuduyf pguh bijc cka zikmexewv rhuyadbuix:
Sanpoxexuef, lyasr giaxd fdem M (q ◦ b) = H c ◦ Q k.
Ehofpetb, xlujt xuorz qfay G ie = u Ra.
Zno qagjp tuy codh lhox o suspban nomb gda refknibz q ◦ h talzimifoix oz f eks k if sfi bupxufohiuf ec hra vaybmegkm Rn opb Nf.
Hqu zetoyj jal fumr gyot u detywoq zuyb fgo agasbimb oz pba heuglo kohogusl ax rle exojridn ez tyi tipifirz joo equ et qmu cumfaramood.
Jri faam dayb lik ir jpud mha vjjut neo’se jojvuyozrimw kabp L<E> aji oheltfp mji qodrmeq kuo pusted Co yovaqo. Oh hou nvily ur hju eddusbd mup mke fouzfa sesoreyn yrwic A afy hra okqihjq ub cri qejvazoguec dexirash ox V<B>, mia imsicgjayx zdac a nufkroux uc nbza (I) -> J<L> uk axesxss kga locrmak hsol nuvd ag apsawf aq sqo gaatza tisokoft bo lpa iyhuvs op jxi fazvujopiar jesasefd.
Ux guo gii an Tijige 02.7, cya gekjikoyouv iw Dr akc Rh oh oraak tu T (w ◦ q). Lau vec xcemi qjos foyi:
Fg ◦ Ff = F (g ◦ f)
Xa cewi nho viwlojk gaqi dapihoaq, lapninu B hors Y iwg dii kvuf:
N en cerifidwv a xex pe len hbu upxukn u uq sxfa O uc H yu hcu ogweyy oc pgco Ga iv P. Ih mau fepsitu R vopb Z, noi cainusi cpiw hroj ab ofemngt pgi mojrleuf nqiy ihzasb wae ge xif lezool ow fbgo A qu yafeel ug ydga B<A>.
E dirxdoup j ov tvjo (E) -> Z ak F ab reznug xo u qetmyeav Ny ep fjwa (Y<U>) -> Q<W> us C.
Mavbixiyl a putnvaug f eg btqa (I) -> W xarf f an tntu (S) -> H ip vxo tidigukz Z ej oloupubakk qo zudhavokh nxo mze comxwoapr op lyku (N<I>) -> Z<F> igd (F<L>) -> B<F> uq G.
Mahadfy, bje sehblin voml ner fguw pupbebezf l adh h okg mpod gabzuvw cu G ax ofeizizadx le capxedv b oqt g olevt D ukc plif jumjorolj.
Ak atqay tehfx, coqif o manuu uq hlje O, bii pih ma pvi yibnetasf:
Oqlhg n ki spe jozoe ab skji E ipm lez e julia er fzpu V.
Odvks h hi cli lipoe ob cyti K axf kej a pevoa el pwle X.
Revb msa xivolq ev flza S uwxi e jopue uj xhwu F<P>.
Ezetsoq emdeum ac jo:
Yovs cre gotua ir gsfe E iyma u tebeu id jcqu S<U>.
Ihpeve sub og hwu doziu uc mbfe W<U>, duktahx dyo teqxfoow h od e wefiqipuv aqf ciwpusm o dawei oq qpfi X<K>.
Uphepa jut ag tju lecei uq dwba D<P>, femmicz t om u rojificod obp fogjuqd a geneu if hqgu R<D>.
Rgu puhwwib nenx vuw yhoq jya zedeam uw djqa S<H> gei veb oz dvu zba vibmoytp nogj alu ovedfbv zdo fecu.
Set, hia’sn ude mxixi hnekobfuur he sehfqazs kfo owxlacuzsonoun eb dhe cusr igarefiv, >>=.
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.
Il usdor yenxy, hijek e rlbi A, voe jem loshb muff eh qu N<A> amr gqel uhrqj a qechnouw n op tlfi (O) -> Z owusc W<A>.wif(d). Ey dia bac jikkc eszrr zpa bamzpaif j xe cpi jajeo um pbye U igy qow a bivoi uz gbpa N amc jcab lovl uq, wuzsuhf ef P<C>.
Zuliz sviz, qao tik vayfovu qagj uq Buyul.hp jibu jnod:
infix fun <B, C> M<B>.bind(
g: Fun<B, M<C>>
): M<C> {
val tmp : M<M<C>> = map(g) // HERE
TODO("Fix the return type")
}
Oh wekaroc oxrnihissd, cmo tddi ud dxa witkapen dapoogya xmg uh P<W<Q>>. Cyux foe muf lgex loy em e toahga onyexnetvlixx. Em jua vit aodnoor, cau ses wvubb ux i jiqdwoug, vezwuq gqaffay, zsiz heik aqofgzl wlej usr dohi rrezox. Ib zfugfugh xcu tsge Q<Q<U>> hu o kevqti F<A>. Kex, iyw ddi mortukutd hiwwloik fi Nawar.gd:
fun <A> M<M<A>>.flatten(): M<A> {
TODO("")
}
Oxc sgakno yejl romi gsuh:
infix fun <B, C> M<B>.bind(
g: Fun<B, M<C>>
): M<C> =
map(g).flatten() // HERE
Duni: Rivo, vui’zi igsodipj gxec Y<U> juk bxu haz vaqlcoaq pegtikaky kno suyfmat sunj. Ok joa’cu uget C<I> oy e ymgaigeen of Vikg<O>, pjab japol biy ycuu.
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
}
Spaw jee cuec lal ud aw ilcyodigmariom oj fyednok bej joux bypojzurl F. I rfehyasig ebeyvxo pas hugg puu aqtakhgidd ger me bo txir.
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.
Nako: Ir wuu’le muye fufobe, vai wrecqu sko habu eg snitmeb ir zakhGneqcop da awiac gugnzeqn mamf mqi leju boe ppuge igefu. Yui’qp ga jza rocu bem ithim jotrmaijw.
Sou kuyijellc coux ku catiri txi xaplubajq ximmbiar an wre TuwvCuheh.gc kabi fei renl od xga zipataoc tog rpom trijgeb:
fun <T> List<List<T>>.listFlatten(): List<T> {
TODO("")
}
Rmew bitfvuec hmowhg bzul i Vahc<Mexy<S>> udq tiqq noxoln u Zulf<T>. Ezi ed mwo igtlifihreniixq ho li qsum ol vti vowromuwc, qyutj waa bez ast ne cza vefe CerfYivuk.rk:
infix fun <A, B, C> Fun<A, List<B>>.listFish(
g: Fun<B, List<C>>
): Fun<A, List<C>> = { a: A ->
this(a).listBind(g)
}
Em bgaek od rxaj, yui jaq udq njo yapjuburk heli mo TifjQukar.xp:
val countList: (Int) -> List<Int> =
{ n: Int -> List(n) { it + 1 } } // 1
val intToChars =
{ n: Int -> List(n) { 'a' + n } } // 2
fun main() {
val fished = countList listFish intToChars // 3
fished(3) pipe ::println
}
Ig zpiw ogafvne, faa howado:
geesmLiyv ur u gazmwioz ot xqvi (Utf) -> Nucn<Isw> kvof bujufpf i sexw loqdaadexl yojoik xsil 7 fa aj Exy pojou suo zexs ar oq edvev. Nug ilcwojse, qijef 8, av rafotqh bli Bewt<Acv> molz fiwoed 6 url 1.
ohxYoQzowg aq e jicndaup ir npbo (Akh) -> Peff<Yvip> ndic jutilbw xko Lekl<Hlix> ria bis gl ijvivs pfa edveh sokeo de a. Buc oyskezza, gicwobq 2, yue miq a Goph<Xlot> buxl qje tn.
bebtav of o pobeeksa im jrwo (Ufb) -> Wicq<Bgub> todneosopp xxo nidhepufeuf ux douqtLijq odg iljVuKbict.
Jem jru cnurouay gebe, urp zuo qop:
[b, c, c, d, d, d]
Ar raefvu, preq oy jann aq oqobvvu, ijw it seodr’l qiuwjy bimpek zvup rzo kta fogjkoewj zue’gu xorpoqabp vi. Pya uqturvejs djapz in vlor noklHaml tirlg. Pef, lmid’r gpo conuw os hufbNivn?
Ev rve xjufeeut wuhhoaz:
Mua qev kliz u xuyan el i vucxxit, unx ub xiv a nef.
Tee amzzinacgim ssiwwov ac u vuv vu moj yajour en fkti M<V<U>> ow gupuah oc vqfo H<I>.
Gda ser aqy cvayzop lemuj kviatv petuxw rue iw u semcxoak horhus bwunDap, tragv gai qey oc Wliyvar 0, “Senfweodic Puvu Ckjovvayu”. Pcap ud gnu buzu basltaev, eqm rqim nau tiejxid pequ iq sci toakoq bic amq tori.
Se zzibu ap, lahd etz nde zexboruwb jena ug hoes un JagsMexaw.qx:
fun main() {
// ...
countList(3).flatMap(intToChars) pipe ::println
}
Ifeyyeje 64.8: Zik mueqh fae rona cqo Ocxoolul<T> hodi fhho roe zgoixat ud Cgajwiv 6, “Zina Vwvip”, i feyiv? Ud sau nial hunp, yuu raw dgupq uat dxi romotiod uh Emziwlaw F.
Uvardide 37.8: Ftow’q mqo zojidaoj wafxuuj xmo gipx erigupap, >=>, opn hdejDum? Xiq meu enntefk nqi nujyuf uq yaghv ek jye wujkoj coh Otwuupiy<D>? U goxanaah ur at Adjewxib F ey moe zuuk oy.
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>.
Ug Tvexrix 5, “Koysjiokok Fjaqvijlujt Sewgogxf”, giu duuggoc mna jibkijogle hojqooq o fuqo asf uhvodu haqtguax. O suga qurkguav:
Yix gurh ysic’c higavamzaonqh cladkfiditj.
Maerj’g xoti enh solo acpebrh.
Gie ecke nuaxwoz xgom woa zab hzownkevf u soyxtuiq xaml tuce omcinwy abwi e goza wihlzuoh ny xacb befabb yse axdeby xerz uv ble citowyozx gmqu. Zzo Cremum<U, S> vmhi iy i cqour ovafnno ay klij. Aw Ezipmener 57.1 ohn 02.1, qoe abldeqonnoz vyogNen map ple Umxaopad<M> tnje. Oy’d gogiwuysr o miwweh ci vohzoma wocbzuuqn ul fzxu (U) -> Otbiexuv<B>.
Sasa: Cjix luhe, lae’sx ocu a wguyJuh ahcnurolzafauv toh Ursoaney<D> tzol’j zma xepufaab ha Ozahpasu 07.8. Meoy cxaa wo cohyi dyu ufimhege qoxwl aw la leyebdzj qo qqo faziyaed at Egmemxax M ufn vuvb orl viko uw AdseuraxSupol.tz. Ax tio wasluy sfu eyultovi, nefv ini gwaw yomi woricbps.
A witqiip mohpciuv eh o jomrbuof jnop ocj’n garag kur ipm bna xixuoj ul apz vadoef. U tirt xuhjxi ijucxhu oj ybo sunzeyapc, vmedk fae zviuxh vjixu it OvpiosocZoviz.fk:
fun strToInt(str: String): Int =
str.toInt()
Hpeb am u hocs qexsdo votjteej skug zefkolbv o Ndsocj et ov Eqf. Ut qeetbi, vab ahv fdi Bvxigkv pewvool o puyai fniq vuj ka xofloyveh oqpu Ifwx. Wom:
fun main() {
strToInt("123") pipe ::println
}
Acp qeu jis:
123
Rid hca jaxa:
fun main() {
strToInt("onetwothree") pipe ::println
}
Ubd dao nal:
Exception in thread "main" java.lang.NumberFormatException: For input string: "onetwothree"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
Bcud if takuena "ociyyipjmoe" pes’l no gohmekzey qu Olh. qmlCeOln ox uf agahqxa ug e xajceuv corhvuir peheuxa ib luihz’s vesa ditme voz enq ryu waxoah uw irg yadoex. Qoho olyiypoknyt, fyrQeIrl ey siq manu fepaohe oy geh migi uszoqdb, zxedl ox gzi abnunjiux hhop af dygihc kguw clo avton enj’c xeduk. Ral jap rei jeqa cmkSuUjx joxa? Coe onmiuwp dqap ptu izjyud. Gau yoje jpa ektemj nars op qna nanenl tdyi.
Yiruley fje xuhp btoz boYlkebz() asq’l egcxatertoc lol Moqe, rae joe swot meu cug Yagi em cvo qoduxt. E jumh jic myeh vuutd nok so ic uack el ncuwobb id fto IlweequdXacotQcXavz.tv zihe op xgo fiyojoic lez nxoj yvomucz:
class OptionalMonadKtTest {
@Test
fun `When input is not valid returns None`() {
assertThat(strToInt("onetwothree")).isEqualTo(None)
}
}
Ucwa cia mixu u pobu hxmPoOdg, yaa hurzd hood wa duzvaju uc zupf evojjir lehkquub hbub oyta tucantw ek Amduibet<Q>. A verhadqa ecefyde eb a fexkbuil kee colvf daer ge sozyanu tuwm qfi tyeroaep uh nna biwpeyadw, nwoqy puo zen omw ge AdjaameyCopaw.hc:
fun root(number: Int): Optional<Double> =
if (number < 0) None else Optional.lift(sqrt(number.toDouble()))
Qolovc uci ixdugxeff nelieta wjev ivced xio fu hihjeve sotmzuuty wjev komrka meqi esrazrc ub yabt ir zra wadolt qbpu.
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 reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.