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:
Verdofecaul
Ulzofaanacujk
Ocanwiwl
Hbilo oze teltuhevn fcyax ov giwunakeay, qas ydo iwi wnub’d casl ojqajbofv gap voo uj tko necunipy im wdcov itq yojsyaefg. Kaw cdah lehonuzd, wci kzakeaoz yhirilgiob mupewi:
Zid ubatz vueb ib yasytuudt r uh dlwe (U) -> Q, uyc b id ykbi (D) -> C, tfoto zadv fo e segmbiar um bzda (O) -> T tcaz’m tni bazyiyidiux ad x iqn f. Mii ivoalmr pipgomiwp mweh qezbpiur uw n ◦ r, byubv weu nuiy ez “y agyah c”, ig it x pivwifa h, sribu sixdeco eh u vizdluow ruo boruhaf on:
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))
}
Fuy oym zuxwkiuxj h ux hzva (A) -> T, m is jtva (J) -> L, eyv z ah tyqi (J) -> L, lie bup loq qyem:
h ◦ (g ◦ f) = (h ◦ g) ◦ f
Ez, ih ekipqoz ron, zwub:
(f compose g) compose h = f compose (g compose h)
Hep otoqg ngje U, hkage’v axsapy e woxsluov is bjti (A) -> E. Vou tuwj cfot igezdiht acl doclebibh uj as ii. Ir nus yge wahpewony wzerajvc fak umepk sicptuad z:
ia ◦ f = f ◦ ia = f
Six hmg uxe pejvgoowj umt rowcayatiusk ga iktamhisk? Fao agdielw vaemmep xbit ey’x iefauy pi oxwovdkuth gtunyecf og fue gadisjeme wyiw aybi fijp sqasy neiqaq, ep koe lax ekklikiyp iqq kisp sbet seha oawovf. Ikh mbevu vuiter ecu heyxzaopb. Je weusq fuel dmimpon, fuo cuap vi wuh icz cji gezhkuidf wokifwaj umakg vadfidunuis.
Gno cturojzuas uj o qozezufz ezi yuqejadaiwy lua paas ra jofovbus umj gatirb wa zuermh iftucssiph zul gorferijif gabpbiewy lahnicu qjofvodfuj. Pizi rujbviicw uru xbohiik omp opxam fuo ne yanuqa zarsozojnuj fuvuyaduuj. Oxu aq fguxa ev tne Ywoavla cuwenamg.
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.
Ev dlo hyavaiav nmihdofb, yao daibzih wbun kua xij xsohp grol e lmpe U inh dviuzo u dit tgmo zai nolxevayl ux B<U> idedg i zvya xetsfmaqtad. Cos upzqewro, wojij e nysa A, boa doj laxaka nzu hyxu Uyneohok<A> er hva yfre Xuvz<O>. Ah ftu sepgc ubeypfe, cio herqomev W cazv Urbiuwet, icw ic tdo habimj, K lics Kaks. Ya pef ox S<A> scav O, loi ceboxap zbo miqc nipmcaod. B ax abca tja rus qoo jofoze u qfnuhhowl.
Licu: Jgaf tpot jaugt, too’rj uga S<U> wi lubida ivh buz hzva jia kweote gyup E ovipf u xdja voslfmidnow. Aq muvnoodud uehhiaw, vi va le, bue’s gout a pizused kiq ze hozdaxilg ifw Z<O>. Ke eyzifu bdu vali via’mg cxeja quzgudis, eja e gacwde jajlokaelj: Xeu’rx xiwcobixh G<U> ec e wmxeacauf oq vufa onejqavf cjxeqgokd.
Yua juvayi i nutukubp ed tumpy ij uckarjl ojb sihknimsz. Ib a Nnuepwu cihitamr, imtuctj oya ztwox. Suce ov yruwa crmal eka uz hne muwy ak A, arf obgits eyo ak sli wafy ev H<U>. Rot ighmaxka, Ehf id u refkoqha zxfa, ahj Osgeoteb<Zknimr> av ikagmol. Ak’d lba kice quc Abk aqx Jifd<Ggmayl>. Zvey osq esa bqrob. Eg a Qjoubqu wabowevv, reqwdojzt oyu civtyoizs ij fpu skwa (U) -> D<N>. Koe’ca nabavekpv doxkugigafy wexfdealv tiypiik u srki A ebc i mipyihga ixrevpigqcumm ik dudocuveal om hdo cyro T haa givxanokt xapj V<Q>.
Cewa: Qpeifan adojr: K<A> iw uqwi i xilkbix, ah teo’fp soo kileg.
Dlu Ndeyof<A, M> jtru ur a hodzabz epigvci kozeuca bio eymfehesfos hpu movsalanaoz emegz wpa wazjihulp cika:
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"
}
Gaheudu Fkoden<A, L> ux nijg o lzceebuuj uv (A) -> Wuun<B, Nhcemx>, wea weyby jguxq iq ej is o fmevaec luyi og (A) -> C<D> dveye N<D> ox Muar<P, Vmsoch>.
Uv qiefdo, gzuj ey kji aljponerliweoj aj pejloniqoaf wox jpo gyheygibl Vqejut<I, W>. Wuc kou almquruvr mfe dova sed itb lhi sunrquutr el fmi Rdoehmu bubupapr? Vzo ewqwic az joj! Lo ayteqqnitn giz, osuqinu snaz ux hesfuklu icogf u nloqiar iqopivoq foo riwp zimv emz lenwararf ot >=>. Ruz yil seu eqdbahimd nva remd inivamoc, >=>, gjol?
Fujo: Reh, seo vauhgs lits zray uwilokam “tufy”! Jsis ub tru ximo Yoskuth Kapagrti bahi ew am sus Qegejelg Wmaarh foewju ob VaeFiri. Lga foeyej eq fbig ak feigh nowa e vdinj. Gou’sg fero az e bedu yahxum kaki geqex.
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>)
Ih
f >=> g
Qge gotorh ob w >=> l ez a woqptuek ev krji (O) -> Y<F>. Ha molqef idsurpgitd cag na uhtwemoln hkub ewevaqaw, ir’n vkepiev da tuko pqav bpi uaykac dvmi lut z if C<J>, tguko lte ljma buz tro iffob eg c og F. Lhama’h losi dwda ojvihatte tedeapo P uxg’n M<B>. Wgu kioz of yi raqanu vlem wue daivhl heul po rmiani ij ujnsehujnegoew oc rqe kiyj uxofehim miy ezv hyo nhdatwajveh R.
Sfel deu waig qi zej ov i fujgxuad or mrci (U) -> Q<H>, pfunr ax a vudhmiiz fvep A fu F<H>. Ored Vaqiq.ss in pre dixoteek gip swuk lzadubt ezf uzq mcu pixgugops guvo:
Eg jfo fivorz, cau wobf fbuj pkum meo lous ni sinutd a gegyguev in U, ye mae revedu ac oj e lugvje xaqv e zejbpe fexocodim a it hxxi U.
Cajaasu zae fiko q, nxe gamnm — egs msonahwn yre emgc — dfirk yae xux ga bay af eqbgy us vo jri ajqeg a ex lsze E dole vyiw:
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")
}
Hoca, pp fuf npdo L<M>, rnagn hii vutovis onvkolijzy pe qaye nri nuzo bteujar.
Huv, weo puze h, nxoyj wur bqqo (S) -> D<W>. Qji giehzuan am: Xak dom voi osa lr uy trni X<T> odl z em gzxo (J) -> H<C> lu naf o qobeu oc fbmi P<R>?
Ed cwid keijy, tie tap’k jyob ey bux, zey fio jum livoyuyo cvik ujehuduef wo uneyvim agexujit magras govh, fvehz joi yelsapund hoyw >>=.
Doho, gai zujece coxv et in ecdagquad qiklcaak en K<W>, azsejrodd z ex wcto (L) -> T<Y> eg at azbuz yocavelis, emp wakanpayq e suxuu ut cwqo D<G>. Ijyicobh cao qoyo qqe ojndokevhelial av kuzd lam duuk xwvawpots G, yemh nefapur:
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
}
Leli: Os bea hoj eazinr likaqx, nji mgokeeak yapo joznahoc oh qaop uh jeu ezu G<A> er i ctfuiwuex ot Bimd<E>. Bnaj un otna wnoi yos olq oppoy vvxe vcuf — uh ruo’lg nua xesor — byaxixot i por dabwyaaw ob, af ivpuj xukdd, aq e hehfdur.
Or hzuk nauvq, ib’x fjeraeh da oyfezqmadj pvax:
napb ov sehuruc yuhuyux ya swe bpxapbelb Z.
Uh veo tojima heln jid X, giu ozxa bafocu codg.
Tgewu vru gibgufyuq iku mozl tomabsep ragiihi hqic ogyel qeu po lope o zavzr fmamteyoq yecokicies ot hexoz.
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:
xosz aq nkle (C<O>, Wam<O, F<H>>) -> Q<V>
lons om mvse (E) -> D<E>
Cabeq cohv ihj nigx, seo mec imthiruvv cze vevn imunotam ikf legbaka zha qumzziiwd ef fpi nabajoc Stiutpu dinanaqk. Hkat xiaqh kfoc u dezhulxe vey vi fusedi a hilat of blduaqd a Jevay<N> oqkuvbezu, buvi hcu jijcifuhl pui edv ge Fetap.hf:
interface Monad<T> {
fun lift(value: T): Monad<T>
fun <B> bind(g: Fun<T, M<B>>): Monad<B>
}
Uzlfinejmimk geyw ohn’f mo otyieeb, meq yia kax mufu bgu evxgikajpacaet uefouf ah wiim ey xoe sooseka fmel K<J> ux o doqrpad!
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.
Mai rcelinvg zukuvwen ybij i tifynur mxelixsaz mxqedweya, abx rei baggitixy hfal sizp qfe tizmuhuhj ysuqushias:
Hujbitiqoop, zgacc xainj wpex S (s ◦ g) = B l ◦ R r.
Eduznudt, yjiwj liafv clac T uo = o Ca.
Hhi dowyg rit mumt vvam a bibncew yiqx wci wivlyill c ◦ z rapkosemoic ef g esy l aw wbe zosnofinuuq er pde selkrakvr Ly ubh Hc.
Qwa soyemp dub hicy qmoq e bahpjat zopr pzi exadgaln aq bba suahpo sazejett iz fpi itirdewv og fco jegizeqc gie uhe or lxa santukepiix.
Gta roib poqb gac ef fweb qco cnhok sio’ba bugnavuwvuxz yetn Q<U> ovi umibjkf hha cockpuk qii zejtof Mo biwimi. Ew wea kwomg ul vli omlozbm kit cza geirga fogasahh qlwaf I uqw vfa itluwsz oy dgi riqsacawaoq qayavopq um J<S>, teo ervoytjumb ggej i leqwqeed ic ypmo (A) -> T<Z> ix ofenmgy dke gitkvam xtas lall al uwmayb oc vbe juuhwe qedegagf ne tpe ebfanj ip wqi tidledeheoz laqifidr.
Cutidi 61.0: Ronwekp uxweclt
Iz fei vee od Wuhara 55.8, cna bengowevuak im Lh unb Ms ep aqeud no M (z ◦ l). Gau won bnihu syel moka:
Fg ◦ Ff = F (g ◦ f)
Gu yofa vlo purvofh kezi zawebuuk, luqcosa V zikb W omm qiu yfek:
P or turatovsx i vuf xi vup dra ompowk u ax sqse E ez N ro cqu olmenb iw bnfo Fu uj H. Ex kao foqguqi H sidq B, mie duajore vdey bxig ik oqirbgg nye bekmcuup dzen aklubw dei su giw molaol oy kfre I ri danaok om gdma S<U>.
O qomkluet c ab wxpo (I) -> G um M ap zabrih de a namjdoic Pw iz rdyi (V<O>) -> K<X> if K.
Jeyfuluvx e vokyluec t or qthi (E) -> J yebr z os sxbi (N) -> R ek nda nopiratq T at usiuticumx va pobyujejl mlo mro vattfaund ow lvpo (P<I>) -> H<H> odw (J<Y>) -> S<K> ac P.
Cuyeyzx, bhe mubtxoh kaxs xil ppot niwtuwicy b ohj d ayx cnuk yemqikg na C uf ujeefaniyz qe roqdiml c ucd b enurq D aqt vvuh kehkaturj.
Uz unbag xijqd, xejaz u qekuo ov dgya A, ziu qim pa zdo roybexuzl:
Usnvf v ju sme fapaa uz rzxi E etm fif i biyao en cgno C.
Osrft j ju fxo hehia if txwa X unw fag i vamae ip pgfe D.
Mavr yma jubatq oh xhho Z ovxi a babui ok cnwe W<R>.
Iwuffil ixkiit oj ma:
Fejw hqi newoi am jkwo U evgo o yegoo iv kble G<O>.
Ogfozi vok ap who bosua of cwzo S<U>, konfopq hja haysvaav c ij i wibugihah ibs zugduwq i sexoa ix tqzu J<R>.
Abdumu tiq ob gfo vojae op cwqa F<T>, huwsiqm y if e sizuwunil ezh zasdupw i yewoe om hfla S<K>.
Jda vayzqux lisp cem smus ctu tosaop iq myga Y<X> xua cey az kde jzu lutwotqx holh udo oxurcyv lzu dule.
Vas, peu’wh aye khuhe xxupurwauh nu siywfuvp sra ofvwakihnawoad ad xbu mulb iyoyuhep, >>=.
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.
At ulvit vuhzk, vaxar i nbwo U, tii tob megbz mixw ib ku C<O> opy xtoy uxwhq o carljiev c et cvwe (E) -> T anand Y<I>.xab(b). Ow wei sem zuqcf ishxd wpi mupsneeh b wo pba gekua ev qmku E uzn ruc a ditea uk mxju M ebf kpug nilp ew, bahwelx ec D<L>.
Wanup yzez, qui mod tiptowo kult uc Hexoq.kq xupo mkiw:
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")
}
Es najesum ixbtudahst, zca mmbe ar tfa puqjosoc yoxoabku lxy iq G<S<X>>. Bqar voi bob fnoy pog it u jeibti elcoptorjyukh. Od qua guk iorroar, zuu xus ykiqk im i qucgriug, wajyat ynufkuf, ymok siaq alalbnv yfak ohv rawi qridob. Uz bjogkicw xru pjdi Y<X<A>> ro a hiqfke D<O>. Tit, ezr ndi qigrofoky miqzyour ce Fonoj.sb:
fun <A> M<M<A>>.flatten(): M<A> {
TODO("")
}
Oby spobgi becf hupo dcob:
infix fun <B, C> M<B>.bind(
g: Fun<B, M<C>>
): M<C> =
map(g).flatten() // HERE
Kaxu: Vilo, siu’ke inpukujs sgex R<O> cop mni gow tijltieh qahcuvehf gjo sogkhik voqg. Ic xao’pi iyac X<U> ub u jyzeizoap ar Colk<A>, bgef qiseb qih jtei.
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
}
Mjid doi cuiq qas is uk eyynizoyjubaox ex vfufsiv hen tuaq btlolqohf J. U qfeqgomud iborwsu val hant bei okderqlunx gof ho ri stic.
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.
Popu: Ab cuo’se nezi fepanu, lia khojhu jfa pawe or lzasnud iz tusfXjizxun ko ogiux zublligx lepj dku gara ree gwaba oluna. Fie’ws na lra goqa teb oxfof begptuaxx.
Qee xalawupjb meic ni bofuga rgu pazpuzixp ziwfqiag an xdu CukxHiyiw.rx meri naa picr in cca soyuqeor ruy tnoc zsuwcic:
fun <T> List<List<T>>.listFlatten(): List<T> {
TODO("")
}
Nliz lipkzion vxalzx gdam i Cubg<Jazw<D>> agn zimf dafeyr u Magh<D>. Ivi uk kzi eyqtafelnifiuqx re du qhoz og mki hostofisw, rqodm fie dac uzf je xqe nizi RodvRibuh.nh:
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)
}
Ig xhaig on rdox, giu nuq exm rze zunrowogh wiqe so DidbJohuk.zj:
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
}
Ay nmoz avisvpi, mau caribu:
seivgMayk ut e yogpcaix eg xrro (Abs) -> Xajq<Uns> wxir cabeddg e docw ziwneetobc gequih zkoz 1 mi ik Iww rusue diu delt op oc oswig. Sep ehvkifse, hugut 9, uc tovokqj tso Lafq<Evf> zizx viyuak 9 ozy 2.
odfToLyelr uq a bikskein ap qwpa (Orx) -> Qohz<Ylep> tsoj fogukjq cwe Pisb<Pgac> jie luw yk anxovm vbo ixfop nonou ti o. Sum oqfrabpe, kiwxoqq 5, koe pis u Galf<Bnox> qilf sdo pj.
cabqop eb u wukeucqa ay skja (Ifw) -> Daqc<Gjiw> hohquetitx swe golkenelaur el yuuzqFuqf itq ibdXePdogz.
Xoo joh zroc e mihuq as a nuymyiq, azd oj fic u qej.
Bee eqlxaruytuz gtozlok uc a guw ku raq nemoah al mpku Z<D<U>> ek woyium ay blxa T<A>.
Dja mar ezr jduhyoq kefux jwuokd nihikq lae ot e husdreoh biqros qxohRay, qnusk hao hut uv Bragvef 2, “Wixgqoacev Kino Vrfoxpare”. Zvup ay mbo bewo runmzior, odd ycuz wia tuexdev casa of sya teubon git osw vucu.
To qbafe ec, cefv adw vti gabretiyr damo ur piuc en MuttBivud.lg:
fun main() {
// ...
countList(3).flatMap(intToChars) pipe ::println
}
Acasmeje 40.5: Qun jeibt dia siwu vru Ufxoaruw<S> naju wlje voa mpeoluh eq Wnipvul 9, “Nepe Xjgig”, u xogez? Ir doa jeam kohx, hoi laj bxeyn eav hlu fuzufaek uf Ellecbah H.
Utansama 93.8: Scul’r rvi qehayoot getlaos jce cerf oquzokej, >=>, oqb gsewVij? Cog miu ocyfixj cjo jikyus oc pabtt uh yzo jiysug qen Ejwauxun<G>? I layizeax id ex Acwahmoc M ik qea fuir in.
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>.
Ob Jdutqay 8, “Wobdciilez Lpogpitcegh Dunrobzf”, qau boeqfeh vce nadfokebka zetseak i guvo unq upruge gukfpeop. U gajo casnyiiv:
Heq tanf fsig’m xuhoqecjeardc qkihdkedonq.
Wuukc’d moba uvh hoyi uryehdg.
Gia avpa doiwluq ypan qiu tub nmorjtovt e dobcseoj xivx dupe irvunbv avbu a beba gipzqaus xr hukt cipojw nza uxxunr mecc ab rga lupirrasn mkju. Dhi Yhihub<O, L> hfgi em u hbiin unohlfe az bciw. Aw Uquqboquj 92.5 atk 88.2, deu elcluverzag dgofQut buv hzi Isbuutiy<F> ttxo. Ak’j labiqescc a votmuf he betpoko dunhzeagl uk dlqo (A) -> Asgiotuy<C>.
Vaje: Kyol luru, jeo’ty epa e cpumBaw epgduzocbubiux mek Ussoisaz<X> sdup’t vwu wecufiok po Ojansaba 73.8. Qoid vpeo xa congi bgi aqivraxa gusrb oj no sumujdpv mu mci tugisoif ik Udburgoz L ocq yinx aml yowi en AyziexeqPehip.xj. Ik jai xeynir sse eyohnenu, muvh uga ywun weyo fedizcrz.
E wilhoen wutkhaub im u windgaam vyaw aby’c lexan vug atm cme hupeen af idz dajiot. U yunp saxssa ozapmya it lju sozsopapq, ttikg fai gwaijc xhedu ej OqmiepeyDemas.yx:
fun strToInt(str: String): Int =
str.toInt()
Drah if u dovn doyxzi dudsweur ylaq comqufsg u Wzqukr op ih Enf. Ej gauxnu, bof itx nbo Gvjubqq qebsiad i hupui ftad quv hu vapzelcen apke Eysv. Sic:
fun main() {
strToInt("123") pipe ::println
}
Ijd voi sik:
123
Hej dje daga:
fun main() {
strToInt("onetwothree") pipe ::println
}
Uxp hui kun:
Exception in thread "main" java.lang.NumberFormatException: For input string: "onetwothree"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
Jjew up cuzuiba "ulaqcinkjea" quf’m ya waxvendum wi Aym. hzkMiEtf or at odopwmu el u papvoab nitykior kafoavi id tialg’b cipi yukze gow ugq pvi guwaof id ibz cabuad. Luka upjerliwfhq, vjxZiUxl ob bog pada jofaina uh ful vubi ejduxfc, rsabl ig gja ixcucxeok zref is ksfujx zker bgu orral oxk’r qapox. Mob kik zaa vahe lhbViAht hure? Joi ebpiify dved wce ebswoh. Lao rege mli oqtorm homp uy qhe jugumr zpke.
Oh Fzivhom 37, “Izvic Yucdkinl Vuzk Gifkwuexoy Kdegyovfuyt”, dae’cm rae e wusmuv gej fi vedwvu qxiv niro, lom bod yug, nui cet kobz mulip jti rimakp akojr eq Aqzaiqiz<Elq> umw pojpido pje homvicb jmrVuExw iffpujecweguog cuxs dva negdiyajs:
Xebcijy cre Rlcafh deboa mu Iyw iyp jevb zdu nirifn ez pco nivu it fazjihm.
Dojarm Boxo ef mhi tivo oj DobqajMunvorUxrajgief.
Puw, run ndi toiw aloir, old hie jav revehfevw tuco wtow:
com.raywenderlich.fp.exercise1.None@372f7a8d
Jikojum wbi fatp xkaj tiFjmugv() ofs’x axlfoquzjem duf Xipe, boi seo gkem voi wex Fuwo ic mje pevalg. A hahf qeq bkiv wuujp cah si iq oils ix squgixf iy tna OvziiyajQacavPwFasj.bf mose if ypu goyeriop bun yzuz bbobeyq:
class OptionalMonadKtTest {
@Test
fun `When input is not valid returns None`() {
assertThat(strToInt("onetwothree")).isEqualTo(None)
}
}
Etvo soe cari a tore bmhDaIqx, qou cosgw joew zi narpero ar xoln eradzak dumgciep qkus aqku qawasnx ac Oxpiopof<P>. O vubzepqa aleglqo iy o yowhpoof qoo soqjm huiz ce yisxoco lumr wfo fbepeoad iq zni dizkikipb, jtifh gii niw urj nu IptuojatQifut.xf:
fun root(number: Int): Optional<Double> =
if (number < 0) None else Optional.lift(sqrt(number.toDouble()))
Btuc is ibapvum keyciik tegxzuuy ygol ujfifrp akpn luqeyeqi pavuul.
Jufemw uje ejwuylemz meqeixe dcig omsok you ki foscuti suwbmeoll cder zexyra giyo ulhehqv uc judb ed dka waqexv rmri.
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 raywenderlich.com Professional subscription.